• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 438
  • Last Modified:

I need verfication - Java Immutable class Is this class Immutable?

Given the following class is it Immutable?

public final class BeImmutable {
      Integer myTestProperty;

      public    static int getTheNumber(  myTestProperty) {
              System.out.println("myTestProperty="+ myTestProperty);
               return (myTestProperty *myTestProperty+ 666);
    }
}

According to my current knowledge about immutable objects they must be final and all properties contained final
Integer is a final object so is this final? or must I add the final   keyword to the myTestProperty  property  to make the class truly immutable  ??

So by that rule the following is not immutable:
public final class NotImmutableEg {
private  StringBuilder sbName;
      void StringBuilder sort(StringBuilder psb)  {  return(psb);}
}
}
So would the following be immutable?
public final class NotImmutableEg {
private final  StringBuilder sbName;
    public   void StringBuilder sort(StringBuilder psb)  {  return(psb);}
}
}
/
The complete rules I gleaned were:
1. An  immutable class can not be modified after construction, any modification would result in
a new immutable class. created.

2. All fields of Immutable class must be final.
3. class must be properly constructed i.e. class reference must not leak during construction process.
4. class must be final in order to restrict sub-class for altering immutability of parent class.

What about the 3rd rule what does that mean exactly what is meant by leak??
It is said by using Immutable classes Threading is easier due to less need for sychronized methods and control blocks of code.
0
Robert Silver
Asked:
Robert Silver
  • 2
2 Solutions
 
krakatoaCommented:
If you haven't already done so, then look at the lit on this here.

It explains things to look out for, which are the types of things you are concerned about.  This is from the lit, so it's not "just another" link.
0
 
dpearsonCommented:
Technically an immutable class is simply one where the data cannot be changed.

So this class as written today:
public final class BeImmutable {
      private Integer myTestProperty;

      public BeImmutable(Integer value) { myTestProperty = value ; }

      public    static int getTheNumber(  myTestProperty) { 
              System.out.println("myTestProperty="+ myTestProperty);
               return (myTestProperty *myTestProperty+ 666);
    }
}

Open in new window


is actually immutable - simply because there is no way to modify the state (myTestProperty) after construction.
(I added a constructor and the keyword 'private' to the member - so nothing else in the package can sneak in and access it).

However, while it's immutable, it's usually considered poor practice to make a class immutable without making the members final, because I could easily come along tomorrow and add a method:

setProperty(Integer newValue) { myTestProperty = newValue ; }

and now the class is no longer immutable.

If the member variables are marked as 'final', that would produce a compile time error and it'll be clearer that my original intention was to make this class immutable.

So this is the real rule:
"1. An  immutable class can not be modified after construction, any modification would result in
a new immutable class. created."

and these are some helpful tips you can use to create an immutable class, but it's not the only valid way:
"2. All fields of Immutable class must be final.
3. class must be properly constructed i.e. class reference must not leak during construction process.
4. class must be final in order to restrict sub-class for altering immutability of parent class."

To answer your question about #3.  This is code that leaks a reference during construction:

public class Leaker {
    private final Integer myValue ;

    public Leaker() {
        myValue  = 7 ;
        updateLeaker(this) ;
    }

    public static void updateLeaker(Leaker leaker) {
        // The leaker object passed here is accessible before the constructor has completed execution
        // That's a no-no
    }
}

Open in new window


This is considered bad because the Java compiler is allowed to produce code that is incorrect in this situation, especially in multi-threaded environments.  You're not meant to access an object until its fully constructed and this code violates that rule.

Hope that helps explain things,

Doug
0
 
Robert SilverAuthor Commented:
Yes that makes sense but what if you change
public static void updateLeaker(Leaker leaker) {

to
public static synchronized void  updateLeaker(Leaker leaker) {
        // The leaker object passed here is accessible before the constructor has completed execution
        // That's a no-no ???
    }

Still thank you for that explanation. It was very clear and helpful.
0
 
dpearsonCommented:
I think even this code is technically illegal:

public static synchronized void  updateLeaker(Leaker leaker) {
        // The leaker object passed here is accessible before the constructor has completed execution
        // That's a no-no ???
    }

The issue is that this thing about "not leaking access to an object before the constructor completes" is part of the rules written right into the Java memory model - which defines what the guarantees are about when objects are visible to other threads (on other processors).  The issues arise because the compiler is allowed to make certain optimizations around the behavior of the processor cache (which if you think about isn't shared memory - 2 CPUs each have their own unique caches, unlike main memory which is shared).  I'm not someone who caries around a copy of the Java language spec in my back pocket - but the people who do could no doubt point you to the right section :)

Now in practice if you add a "synchronized" statement it's hard to imagine any compiler will actually produce code that's invalid.  That's because "synchronized" itself triggers a requirement that instructions executed before it must be visible to all threads executing code after it - so in some sense the objects that exist before it should be 'published' to all threads.  But doing this is playing with fire.  You're still violating a rule and if your code malfunctions in odd ways in a multi-processor environment and you submit a bug on it, the JVM guys can say "well...that's because your code is illegal".

Simple answer is that's it's best to avoid this.  And honestly code that waits to call methods until after the constructor is finished is better code anyway.

Incidentally easily the most common examples of violating this is the old example of how to make a thread:

public class MyThread extends Thread {
     public MyThread() {
        ...
        // This is technically wrong, because it starts the thread before the constructor finishes
        start() ;
     }
}

You can probably find that code in 100 old tutorials on threads.

Anyway, these days we use Executors, so no reason to ever be newing up Thread objects directly...but just thought I'd mention it :)

Doug
0

Featured Post

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now