Skip to main content

Immutable Class in Java

Immutable Class in Java

In this article, we are going to learn how to create an immutable class in java. Immutable class is a class which constructs immutable objects. The state or property of an immutable object can only be initialized once (only in the constructor), and after that, all the properties of an immutable object remains constant throughout the life of the object.
Before implementing immutable class in java, we must read the rules/guidelines provided for creating immutable class in java.

Rules to create Immutable class in Java

All the rules to create an Immutable class in java is defined to make sure that the state or property of the object do not get modified anyhow. Look at the below-mentioned rules to create an Immutable class in java.
  1. Class should be final: by making a class as final, we can ensure that the class will not to be extend by any other class and the methods will not allow to get overridden by the subclasses.
  2. All the fields must be private and blank final: A blank final field can only be initialized only in the constructor, and after that, no method can update or modifiy it's value.
    Please note that, in case of reference object, field contains the reference of the object i.e., reference cannot be changed as it is final.
  3. All the field must be initialized into the constructor: As mentioned earlier, any blank final field can be initialized only in the constructor and according to the rule no. 2 all the fields must be private and blank final i.e., all the field must be initialized into the constructor.
  4. No Setter Methods: Any Immutable class must not contain any setter method or any method which can modify the state of the object.
  5. If there is any field which contains the refenrence of any Mutable object: Then there are some rules for those fields
    • Getter method must not returns the reference of the mutable object: There should not be any getter method which returns the reference of the mutable object instead the getter must returns the reference of the copy of the mutable object.
      Please note that, to create a copy of the mutable object we can clone the object but cloning must be Deep Cloning.
    • Cloning of Mutable object in the Constructor: Any field which contains the reference of the mutable object must not be initailized with the object passed in the argument of the constructor. It should also be cloned by deep cloning method and then the blank final field is to be initialized with the cloned object.

How to create Immutable class in Java?

Now, we know all the rules to create Immutable class in java, so let's follow the above-mentioned rules to implement an Immutable class. To keep it simplified, we first develop a very simple immutable class (which do not contains reference to any mutable object).
class User{
	private int id;
	private String name;
	private String email;
	private String address;
}
Let suppose, Above, we have a class called as User which we need to converted into an Immutable class in java. Let's follow the rules and convert this User class into an Immutable class in java.
final class User{
	private final int id;
	private final String name;
	private final String email;
	private final String address;
    
	// String is also an Immutable class in java
	User(int id, String name, String email, String address) {
		this.id = id;
		this.name = name;
		this.email = email;
		this.address = address;
	}
	public int getId() {
		return id;
	}
	public String getName() {
		return name;
	}
	public String getEmail() {
		return email;
	}
	public String getAddress() {
		return address;
	}
}
As we can see, it is very easy to convert any mutable class into an immutable class but in the above example all the fields are either primitve or reference for an immutable object. Now let see how to create an Immutable class in java when a class contains reference of an mutable object.
class Address{
	private String houseNumber;
	private String street;
	private String city;
}

class User{
	private int id;
	private String name;
	private String email;
	private Address address;
}
Let suppose, our User class changed a little bit, now it contains address as reference of an Address class instead of String and Address is a mutable class. With the help of rules for mutable objects, let's create an Immutable class.
final class User {
	private final int id;
	private final String name;
	private final String email;
	private final Address address;
    
	/*
	 * To clone the address.
	 */
	private static Address cloneAddress(Address address) {
		return new ObjectMapper().convertValue(address, Address.class);
	}

	User(int id, String name, String email, Address address) {
		this.id = id;
		this.name = name;
		this.email = email;
		/*
		 * Any field contains reference of any mutable object must be
		 * initialized with the cloned object
		 */
		this.address = cloneAddress(address);
	}
	public int getId() {
		return id;
	}
	public String getName() {
		return name;
	}
	public String getEmail() {
		return email;
	}
	public Address getAddress() {
		/*
		 * Getter method must return the reference of cloned object.
		 */
		return cloneAddress(address);
	}
}
Please note that, I have used ObjectMapper for deep cloning which is the class of package com.fasterxml.jackson.databind from the jackson library and the convertValue() method is used to deep clone any object.
You can write your own code or use any other library for deep cloning of the object
Above, we have created our immutable class as User. Now, it's time to write code to test the User class. To test, we need to create an object from User class and try to update it's state. Let see are we able to modify it's state or not.
public static void main(String... args) {

	Address address = new Address();
	address.setHouseNumber("A-1/17");
	address.setStreet("Rohini");
	address.setCity("Delhi");

	/*
	 * Immutable object
	 */
	User user = new User(101, "Shubham", "shubham.bansal@gmail.com",
			address);
	printUser(user);

	/*
	 * Update the city in above created Address's object
	 * If, we do not clone the address in the constructor then it
	 * will fail here.
	 */
	address.setCity("Mumbai");
	printUser(user);

	/*
	 * Update the street on the address provided by the User's object
	 */
	Address userAddress = user.getAddress();
	userAddress.setStreet("Dwarka");
	printUser(user);

	/*
	 * There is no setter method, so we cannot modify the state of the
	 * object.
	 */
}
static void printUser(User user) {
	System.out.println(user.getId());
	System.out.println(user.getName());
	System.out.println(user.getEmail());
	Address address = user.getAddress();
	System.out.println(address.getHouseNumber() + ", " + address.getStreet()
			+ ", " + address.getCity());
	System.out.println("=======================");
}
Output
101
Shubham
shubham.bansal@gmail.com
A-1/17, Rohini, Delhi
=======================
101
Shubham
shubham.bansal@gmail.com
A-1/17, Rohini, Delhi
=======================
101
Shubham
shubham.bansal@gmail.com
A-1/17, Rohini, Delhi
=======================
As we can see, there is no way to modify the state of the object after creation. So, we can say that we have successfully create an immutable class in java.
By the Same way, we can convert more complexed class as an immutable class.

Benefits of making an Immutable class in java

Before, using anything we should also know the benefits of a particular. Below, we are discussing some of the benefits provided by the immutable class.
  1. Immutable objects are by default thread-safe as the state of immutable object do not changed. So, we can easily share them among multiple threads.
  2. Immutable objects can easily be cached because they remain constant so we do not have to worry about the state of object.
  3. Immutable objects are the best options to use as a key object in any map like HashMap. This is the reason String is widely used object as key for maps

Pre-defined Immutable class in java

  1. String class represents the immutable object for sequence of characters.
  2. Wrapper classes like Integer, Float, Long etc. all are represents the immutable object for corresponding primitive type.
  3. java.util.UUID represents a unique 128-bit of hexadecimal string.
These are a few of the Immutable class in java provided by the JDK.

Conclusion

In this article, we have seen how to create an Immutable class in java. Immutable class provides us many advantage and best suited for multi-threaded environments. We also learn the rules to make an immutable class and its benefits.
Thanks for reading this article.
If, we missed something please let us know in the comment section below.
Happy Learning

Related Articles

Inner Class in Java
Static Class in Java

Comments