How to create immutable class in java / What are immutable classes in java

Immutable object : Meaning

Literal meaning of the word immutable is “not changing”, “unable to be changed”. When relating this word to a java object, it means an object whose state cannot be changed once the object is created. State of an object is composed of its fields(or instance variables). In simple terms, an immutable object is one whose field values cannot be changed after the object is created. Class of such an object is an immutable class.

Ideally, any change in the state of an immutable object should result in a new object which is a copy of actual object.

Use of Immutable Class

Instances of immutable class are non-changeable in terms of their state. This characteristic makes them ideal to be used :

  1. In caching. Load these objects with static data which is required by the application and use them across. Since they are immutable, the data they hold will never be modified and you will get consistent data across the application.
  2. In multi-thread applications. Objects, in such applications are shared by many threads and you would not want data of one thread to be manipulated by any other thread. Thus, immutable objects would be of great help since its data can never be manipulated.

How to create Immutable class

In order to create an immutable class, certain rules need to be followed. They are outlined below :

  1. Make the class final : This is required so that the class can not be extended and modified by exposing methods to change the state of its object.
  2. Make all the fields private : This is required so that the fields cannot be accessed from outside the class for modification.
  3. Make the fields final : This is done so that the fields are initialized only once from inside the constructor only.
  4. Remove all setter methods : So that field values are not modified from outside the class.
  5. If the class has any other object as a field(or instance variable) and this object is mutable, then make a copy of this object in the constructor before assigning it to the corresponding field of immutable class.
  6. If the class has a mutable object as a field(or instance variable), make sure to return a copy of this object from the getter method of this field.
Opposite of immutable object is a mutable object whose state can be changed any number of times. Normally, we use these type of objects only, unless immutability is strictly required.

Immutable Class Example

An example of immutable class is shown below.

public final class Employee {
 
   private final String name;
 
   private final String id;
 
   /**
       * Constructor
       * @param empName
       * @param eid
       */
   public Employee(String empName, String eid) {
	name = empName;
	id = eid;
   }
 
   /**
       * Getter methods
       */
   public String getName() {
	return name;
   }
 
   public String getId() {
	return id;
   }
}

Class above represents an Employee with name and id fields. Note that both its fields are marked private and final and have no setter method. Thus, their value can only be set once through the constructor at the time of creation of Employee object.

Immutable class with a Mutable field

Let’s say, a new field is added to our Employee class. This field is of class EmployeeDetail as given below.

public class EmployeeDetail {
 
   private int age;
 
   private double height;
 
   private String address;
 
   /**
       * Getter and Setter methods
       */
 
   public int getAge() {
	return age;
   }
 
   public void setAge(int age) {
	this.age = age;
   }
 
   public double getHeight() {
	return height;
   }
 
   public void setHeight(double height) {
	this.height = height;
   }
 
   public String getAddress() {
	return address;
   }
 
   public void setAddress(String address) {
	this.address = address;
   }
}

This class is not immutable. All its fields have a public setter method and their values can be easily changed externally. Now, a field of this type is added to our Employee class. Modified version of Employee class is given below.

public final class Employee {
 
   private final String name;
 
   private final String id;
 
   private final EmployeeDetail details;
 
   /**
      * Constructor
      * @param empName
      * @param eid
      * @param empHeight
      */
   public Employee(String empName, String eid, EmployeeDetail empDetails) {
	name = empName;
	id = eid;
	details = empDetails;
   }
 
   /**
       * Getter methods
       */
 
   public String getName() {
	return name;
   }
 
   public String getId() {
	return id;
   }
 
   public EmployeeDetail getDetails() {
	return details;
   }
}

This field is also final and has no public setter method.

Effect of Mutable object in Immutable class

Now, you must be wondering that in the above section of How to create immutable class, there were points 5 and 6 that stated :

  1. If an immutable class has a mutable object, then its copy must be assigned to the field in the constructor.
  2. If an immutable class has a mutable object, then its copy should be returned from the getter method of this field.

But these points are not followed in the updated Employee class above. Well Yes, they are not followed and that is why the class is no more immutable. Have a look at the below code snippet.

public static void main(String[] args) {
	// create a details object
	EmployeeDetail details = new EmployeeDetail();
	details.setAddress("California");
	details.setAge(25);
	details.setHeight(5.7);
	// create employee object using these details
	Employee emp = new Employee("Abc", "00410", details);
	// print height
	System.out.println("Employee height is " + emp.getDetails().getHeight());
 
	// change height using details object
	details.setHeight(6.0);
	// again print height
	System.out.println("Employee height is " + emp.getDetails().getHeight());
}

Output will be

Employee height is 5.7
Employee height is 6.0

Woop !!! height changed… Immutability Gone !!!

Above problem can be solved by following point no 5, that is, assigning a copy of mutable object field in the constructor of immutable class. Modified constructor is shown below.

public Employee(String empName, String eid, EmployeeDetail empDetails) {
	name = empName;
	id = eid;
	// create a copy of the mutable field
	EmployeeDetail copyObject = new EmployeeDetail();
	// populate it with actual object values
	copyObject.setAddress(empDetails.getAddress());
	copyObject.setAge(empDetails.getAge());
	copyObject.setHeight(empDetails.getHeight());
	// assign the copy object to the mutable field
	details = copyObject;
}

Now running the same code which creates Employee object and then changes the height of the employee will give the following output.

Employee height is 5.7
Employee height is 5.7

This is because we have assigned EmployeeDetail object populated with initial values to the Employee object once during its creation. Now changing the EmployeeDetail will have no effect on Employee object since it has its own copy of EmployeeDetail.

Finally, what is the impact of not returning a copy of mutable object from its getter method in immutable class. Have a look at below code.

public static void main(String[] args) {
	// create a details object
	EmployeeDetail details = new EmployeeDetail();
	details.setAddress("California");
	details.setAge(25);
	details.setHeight(5.7);
	// create employee object using these details
	Employee emp = new Employee("Abc", "00410", details);
	// print height
	System.out.println("Employee height is " + emp.getDetails().getHeight());
 
	// get details object from immutable object and change its height
	emp.getDetails().setHeight(6.0);
	// again print height
	System.out.println("Employee height is " + emp.getDetails().getHeight());
}

Output of this code will be

Employee height is 5.7
Employee height is 6.0

Immutability gone again !!! Reason is that the above code gets the mutable object from the immutable object using its getter method and then changes one of the fields using setter method of this field, which, in turn changes the actual immutable object.

This problem can be corrected by making a copy of the mutable object and returning it from its getter method from immutable class as shown below.

public EmployeeDetail getDetails() {
	// create a copy of the mutable field
	EmployeeDetail copyObject = new EmployeeDetail();
	// populate it with actual object values
	copyObject.setAddress(details.getAddress());
	copyObject.setAge(details.getAge());
	copyObject.setHeight(details.getHeight());
	return copyObject;
}

Running main method again will print

Employee height is 5.7
Employee height is 5.7

With all the above changes incorporated, now the Employee class is immutable. All its primitive fields are final and cannot be changed while any attempt to modify the mutable object field will always create a new object with actual values.

Immutable classes in Java Api

Java has many builtin classes which are immutable. You cannot change the state of their objects once created and if you are able to change, then you will be getting a new object with its contents copied from actual object. Following are some immutable classes from Java api.

java.lang.String
Wrapper classes of primitives such as java.lang.Integer, java.lang.Boolean, java.lang.Double etc.
java.io.File
java.util.Locale
java.util.UUID
java.net.URL
java.math.BigInteger
java.math.BigDecimal and many more…

Hope this post enhanced your knowledge about immutable classes. Comment in the box below if it really did. Keep visiting !!!

Mark Your Impression

Close Menu