How to create immutable class in Java?

How to create immutable class in Java?

Immutable class is a class which once created, its contents cannot be modified. Immutable objects are the objects whose state cannot be modified once it is created.

Best example to explain the difference between mutable and immutable is String and StringBuffer.

String is immutable class (Refer String is immutable or final in Java) , if we try to change the existing String object like substring, replacing character etc. results in another immutable String object, in case of StringBuffer a mutable one won’t create new object if any modification is done.

All wrapper classes in java.lang are immutable  String, Integer, Boolean, Character, Byte, Short, Long, Float, Double, BigDecimal, BigInteger

To create immutable class following steps needs to be implemented

  • Don’t allow subclasses to override methods. (Simplest way is to declare class as final, Final classes in Java cannot be overridden. A more sophisticated approach is to make the constructor private and construct instances in factory methods.)
  • All fields in the class must be final and private. (Private, ensures all fields will be hidden so that there won’t be access for outside members and declaring final won’t allow any modification)
  • Do not provide any setter methods – methods that modify fields or objects referred to by fields.
  • If the instance fields include references to mutable objects, don’t allow those objects to be changed:
    • Don’t provide methods that modify the mutable objects.
    • Don’t share references to the mutable objects. Never store references to external, mutable objects passed to the constructor; if necessary, create copies, and store references to the copies. Similarly, create copies of your internal mutable objects when necessary to avoid returning the originals in your methods.

 

public final class Immutable {
  private final String id;
  private final StringBuffer name;
  public String getId() {
    return id;
  }
  public StringBuffer getName() {
    return name;
  }
  public Immutable(String id, StringBuffername){
    this.id=id;
    this.name = name;
    //this.name = new StringBuffer(name);
  }
  public static void main(String[] args) {
    StringBuffer test = new StringBuffer("Andhra");
    String n = "IVV";
    Immutable i = new Immutable(n, test);
    System.out.println("Before modification Id :"+i.getId());
    System.out.println("Before modification name :"+i.getName());
    n = "Nani";
    test.append("Pradesh");
    System.out.println("After modification Id :"+i.getId());
    System.out.println("After modification name :"+i.getName());
  }
}

Output:
Before modification Id :IVV
Before modification name :Andhra
After modification Id :IVV
After modification name :AndhraPradesh

In this example all fields are private and final, there are no setter methods for them and class itself declared as final to stop inheritance.

String is immutable, hence String object is not changed even after any modification whereas StringBuffer is mutable so its value got changed after modification. Then we can’t call it as immutable class because we are able to change the (StringBuffer) name properties.

To make it immutable class we need to implement 4th point i.e. shouldn’t share the reference to mutable objects (StringBuffer in this case) instead create copies for the same.

Now uncomment this line in the same program
//this.name = name;
this.name = new StringBuffer(name);
Output:
Before modification Id :IVV
Before modification name :Andhra
After modification Id :IVV
After modification name :Andhra
Benefits of immutability:

  • Immutable objects are thread-safe, and have no synchronization issues.
  • It simplifies development, as it’s easy to share between multiple threads.
  • The references to the immutable objects can be easily shared or cached without having to copy or clone them as there state cannot be changed once created.
  • The best use of the immutable objects is as the keys of a map.

Leave a Reply

Your email address will not be published. Required fields are marked *