Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create immutable objects in Java?

How to create immutable objects in Java?

Which objects should be called immutable?

If I have class with all static members is it immutable?

like image 437
Neel Salpe Avatar asked Jun 10 '11 11:06

Neel Salpe


People also ask

Can we create object of immutable class in Java?

In Java, when we create an object of an immutable class, we cannot change its value. For example, String is an immutable class. Hence, we cannot change the content of a string once created. Besides, we can also create our own custom immutable classes.

What is an immutable object and how do you construct it?

An object is immutable if its state cannot change after construction. Immutable objects don't expose any way for other objects to modify their state; the object's fields are initialized only once inside the constructor and never change again.

Why are the objects immutable in Java?

Immutable objects are particularly useful in concurrent applications. Since they cannot change state, they cannot be corrupted by thread interference or observed in an inconsistent state.


2 Answers

Below are the hard requirements of an immutable object.

  1. Make the class final
  2. make all members final, set them explicitly, in a static block, or in the constructor
  3. Make all members private
  4. No Methods that modify state
  5. Be extremely careful to limit access to mutable members(remember the field may be final but the object can still be mutable. ie private final Date imStillMutable). You should make defensive copies in these cases.

The reasoning behind making the class final is very subtle and often overlooked. If its not final people can freely extend your class, override public or protected behavior, add mutable properties, then supply their subclass as a substitute. By declaring the class final you can ensure this won't happen.

To see the problem in action consider the example below:

public class MyApp{      /**      * @param args      */     public static void main(String[] args){          System.out.println("Hello World!");          OhNoMutable mutable = new OhNoMutable(1, 2);         ImSoImmutable immutable = mutable;          /*          * Ahhhh Prints out 3 just like I always wanted          * and I can rely on this super immutable class           * never changing. So its thread safe and perfect          */         System.out.println(immutable.add());          /* Some sneak programmer changes a mutable field on the subclass */         mutable.field3=4;          /*          * Ahhh let me just print my immutable           * reference again because I can trust it           * so much.          *           */         System.out.println(immutable.add());          /* Why is this buggy piece of crap printing 7 and not 3            It couldn't have changed its IMMUTABLE!!!!           */     }  }  /* This class adheres to all the principles of  *  good immutable classes. All the members are private final *  the add() method doesn't modify any state. This class is  *  just a thing of beauty. Its only missing one thing *  I didn't declare the class final. Let the chaos ensue */  public class ImSoImmutable{     private final int field1;     private final int field2;      public ImSoImmutable(int field1, int field2){         this.field1 = field1;         this.field2 = field2;     }      public int add(){         return field1+field2;     } }  /* This class is the problem. The problem is the  overridden method add(). Because it uses a mutable  member it means that I can't  guarantee that all instances of ImSoImmutable are actually immutable. */  public class OhNoMutable extends ImSoImmutable{         public int field3 = 0;      public OhNoMutable(int field1, int field2){         super(field1, field2);               }      public int add(){        return super.add()+field3;       }  } 

In practice it is very common to encounter the above problem in Dependency Injection environments. You are not explicitly instantiating things and the super class reference you are given may actually be a subclass.

The take away is that to make hard guarantees about immutability you have to mark the class as final. This is covered in depth in Joshua Bloch's Effective Java and referenced explicitly in the specification for the Java memory model.

like image 113
nsfyn55 Avatar answered Sep 27 '22 19:09

nsfyn55


Just don't add public mutator (setter) methods to the class.

like image 35
BalusC Avatar answered Sep 27 '22 18:09

BalusC