Immutable Objects

What is Immutable Object
An immutable object is something whose state can't be change after there creation, e.g. String objects. Once you have created a String object, you can't alter this.

Creating an Immutable object's class
Creating an immutable object's class can be tricky. Minimal requirement to create an immutable object's class is, make class and every member variable, "final".

public final class SimpleImmutableClass {
 final int intVal = 5;
 final String sampleString = "Hello";
 final Integer intObj = Integer.valueOf(10);
}

SimpleImmutableClass is a class of mutable object, one can't change its state, once object is created. But it is too simple case. In real world situation is far more complex, you will rarely find such a simple class that has only primitive or immutable members (actually String and Integer classes are classes for immutable objects, provided by JDK API stack).

Consider following example, that has mutable objects as members, though every member is final, private and has only getters (to access) and no setters, but still do you think that it is a class that can produce immutable objects.
public final class NotAnImmutableClass{
private final ArrayList<String> sampleList = new ArrayList<String>();
 private final Date today = new Date();
 
 public ArrayList<String> getSampleList() {
  return sampleList;
 }
 public Date getToday() {
  return today;
 }
}

What do you think about above class, is it really an Immutable object's class? Unfortunately, a big NO. At first it seems like it is an immutable object's class, after all, it is a final class, every variable is final and private and to give more assurance, it doesn't contain any "setter" method. Some may give me a good fight arguing about immutability of the objects of this class.
But then comes the villain, the very basic of Java, the "Reference".  Consider the following listing:

class PokeIntoSoCalledImmutableClass {
public void poke(){
  NotAnImmutableClass notAnImmutableClass = new NotAnImmutableClass();
  List<String> samples = notAnImmutableClass.getSampleList();
  Date d = notAnImmutableClass.getToday();
  samples.add("Poked String");
  d.setYear(111);  
  System.out.println(notAnImmutableClass.getSampleList().size());
  System.out.println(notAnImmutableClass.getToday());
 }
 
}
What do you think, the method  poke() would print? Do you think it would print "0" and "Sun Jun 05 00:00:00 IST 2010"?  Answer is a big NO!!!

So, here comes another rule for a class whose objects to be immutable, either it should not have any mutable field (as in our case) or it should not publish (expose) its mutable members.

But again question is, what if we have to expose mutable objects and still we need that our class's objects are immutable? Well answer is simple but tricky. USE CLONING!!!! If exposed object contains only immutable objects or primitive types, use shallow copy, otherwise use deep copy.
Correct way to implement Immutable class:

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class AnImmutableClass {
 private final ArrayList<String> sampleList = new ArrayList<String>();
 private final Date today = new Date(110,5,5);
 
 public ArrayList<String> getSampleList() {
  ArrayList<String> returnList = new ArrayList<String>();
  for(String s : sampleList){   
   returnList.add(s);
  }
  return returnList;
 }
 public Date getToday() {
  return (Date)today.clone();
 }
 
 public static void main(String[] args) {
  PokeIntoSoCalledImmutableClass pokeClass = new PokeIntoSoCalledImmutableClass();
  pokeClass.poke();
 }
 
}

class PokeIntoSoCalledImmutableClass {
 public void poke(){
  AnImmutableClass anImmutableClass = new AnImmutableClass();
  List<String> samples = anImmutableClass.getSampleList();
  Date d = anImmutableClass.getToday();
  samples.add("Poked String");
  d.setYear(111);  
  System.out.println(anImmutableClass.getSampleList().size());
  System.out.println(anImmutableClass.getToday());
 }
 
}

I here conclude with set of rules to make a class whose objects are immutable:
  • Must be final
  • Only final members should be exposed to outer world
  • Exposed members should be immutable
  • If it is require to expose mutable members, then use shallow or deep cloning while exposing them


16 comments:

Ajit Sharma said...

Nice article.... keep posting... :-)

Ruchika Mediratta said...

Finally clear with my Immutable Class concept!! Nice One... Please do post some blogs over design patterns also

Ashish said...

Nice beginning :)

One that would add charm to this post is, why immutability is good, probably describe some real life use cases, so that readers can correlate things easily.

Anonymous said...

Nice article.

I have one query though "Why Java decides to make String class Immutable", I have posted my view here
http://javarevisited.blogspot.com/

but would like to know what's your view.

Unknown said...

really it made everything clear about immutability in java...expecting sm more articles from ur side..

Anonymous said...

public ArrayList getSampleList() {
return Collections.unmodifiableList(sampleList);
}
// ah, that looks better :-)

Anonymous said...

You can also provide setters in the class as well but make sure that they return a new object with the specified value set. The pattern is usually followed for chaining method calls.

Another approach for providing setters is provide a separate mutator class as in Java String has a mutator in the form of StringBuffer/StringBuilder through which we can mutate intermediate representations (similar to builder pattern) and then get a concrete immutable String object.

Anonymous said...

Nice article but: You never ever should use a concrete Implementation (ArrayList) in an Method signature if there is an interface(List) you can use.

If you release this as an api, nobody can use another implementation but ArrayList.

Unknown said...

Where to use Interface and Abstract class.Can u provide simple real time example

Muhammad Khojaye said...

The problem mentioning these rules are that there are always exceptions exist. For instance, the most famous immutable class -- java.lang.String has a non-final member whose value changes sometime after the String is created. It's used to cache the hashCode after computing it once. :)

Muhammad Khojaye said...

The problem mentioning rules like this is that there are always exceptions. For instance, immutable class -- java.lang.String -- has a non-final member whose value changes sometime after the String is created. It's used to cache the hashCode after computing it once.

Muhammad Khojaye said...

The problem mentioning rules like this is that there are always exceptions. For instance, immutable class -- java.lang.String -- has a non-final member whose value changes sometime after the String is created. It's used to cache the hashCode after computing it once. 0

Muhammad Khojaye said...

The problem mentioning rules like this is that there are always exceptions. For instance, immutable class -- java.lang.String -- has a non-final member whose value changes sometime after the String is created. It's used to cache the hashCode after computing it once.

Muhammad Khojaye said...

The problem mentioning rules like this is that there are always exceptions. For instance, immutable class -- java.lang.String -- has a non-final member whose value changes sometime after the String is created. It's used to cache the hashCode after computing it once.

Muhammad Khojaye said...

The problem mentioning rules like this is that there are always exceptions. For instance, immutable class -- java.lang.String -- has a non-final member whose value changes sometime after the String is created. It's used to cache the hashCode after computing it once.

Anonymous said...

package com.pawan.immutable;

import java.util.ArrayList;
import java.util.Date;

public class AnImmutableClass {
public static void main(String[] args) {
AnImmutableClass anImmutableClass = new Subclass();
// When Subclass is provided the below method as a anImmutableClass
// reference can cause serious issues
anImmutableClass.getToday();
}

private final ArrayList sampleList = new ArrayList();

private final Date today = new Date(110, 5, 5);

public ArrayList getSampleList() {
ArrayList returnList = new ArrayList();
for (String s : sampleList) {
returnList.add(s);
}
return returnList;
}

public Date getToday() {
return (Date) today.clone();
}

}

class Subclass extends AnImmutableClass {

public Date myDate = new Date();

@Override
public Date getToday() {
return myDate;
}

}
So make sure methods should be final as well