// Tutorial //

How to Create Immutable Class in Java?

Published on August 3, 2022
Default avatar
By Pankaj
Developer and author at DigitalOcean.
How to Create Immutable Class in Java?

While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.

Today we will learn about the immutable class in Java. What are immutable classes? The benefits and importance of deep copy for immutability.

What is an immutable class in Java?

Immutable objects are instances whose state doesn’t change after it has been initialized. For example, String is an immutable class and once instantiated its value never changes. Read: Why String in immutable in Java

Benefits of Immutable Class in Java

how to create immutable class in java An immutable class is good for caching purposes because you don’t have to worry about the value changes. Another benefit of immutable class is that it is inherently thread-safe, so you don’t have to worry about thread safety in case of multi-threaded environment. Read: Java Thread Tutorial and Java Multi-Threading Interview Questions. Here I am providing a way to create an immutable class via an example for better understanding.

How to Create an immutable class in Java?

To create an immutable class in Java, you have to do the following steps.

  1. Declare the class as final so it can’t be extended.
  2. Make all fields private so that direct access is not allowed.
  3. Don’t provide setter methods for variables.
  4. Make all mutable fields final so that its value can be assigned only once.
  5. Initialize all the fields via a constructor performing deep copy.
  6. Perform cloning of objects in the getter methods to return a copy rather than returning the actual object reference.

To understand points 4 and 5, let’s run the sample Final class that works well and values don’t get altered after instantiation. FinalClassExample.java

package com.journaldev.java;

import java.util.HashMap;
import java.util.Iterator;

public final class FinalClassExample {

	private final int id;
	
	private final String name;
	
	private final HashMap<String,String> testMap;
	
	public int getId() {
		return id;
	}


	public String getName() {
		return name;
	}

	/**
	 * Accessor function for mutable objects
	 */
	public HashMap<String, String> getTestMap() {
		//return testMap;
		return (HashMap<String, String>) testMap.clone();
	}

	/**
	 * Constructor performing Deep Copy
	 * @param i
	 * @param n
	 * @param hm
	 */
	
	public FinalClassExample(int i, String n, HashMap<String,String> hm){
		System.out.println("Performing Deep Copy for Object initialization");
		this.id=i;
		this.name=n;
		HashMap<String,String> tempMap=new HashMap<String,String>();
		String key;
		Iterator<String> it = hm.keySet().iterator();
		while(it.hasNext()){
			key=it.next();
			tempMap.put(key, hm.get(key));
		}
		this.testMap=tempMap;
	}
	
	
	/**
	 * Constructor performing Shallow Copy
	 * @param i
	 * @param n
	 * @param hm
	 */
	/**
	public FinalClassExample(int i, String n, HashMap<String,String> hm){
		System.out.println("Performing Shallow Copy for Object initialization");
		this.id=i;
		this.name=n;
		this.testMap=hm;
	}
	*/
	
	/**
	 * To test the consequences of Shallow Copy and how to avoid it with Deep Copy for creating immutable classes
	 * @param args
	 */
	public static void main(String[] args) {
		HashMap<String, String> h1 = new HashMap<String,String>();
		h1.put("1", "first");
		h1.put("2", "second");
		
		String s = "original";
		
		int i=10;
		
		FinalClassExample ce = new FinalClassExample(i,s,h1);
		
		//Lets see whether its copy by field or reference
		System.out.println(s==ce.getName());
		System.out.println(h1 == ce.getTestMap());
		//print the ce values
		System.out.println("ce id:"+ce.getId());
		System.out.println("ce name:"+ce.getName());
		System.out.println("ce testMap:"+ce.getTestMap());
		//change the local variable values
		i=20;
		s="modified";
		h1.put("3", "third");
		//print the values again
		System.out.println("ce id after local variable change:"+ce.getId());
		System.out.println("ce name after local variable change:"+ce.getName());
		System.out.println("ce testMap after local variable change:"+ce.getTestMap());
		
		HashMap<String, String> hmTest = ce.getTestMap();
		hmTest.put("4", "new");
		
		System.out.println("ce testMap after changing variable from accessor methods:"+ce.getTestMap());

	}

}

Output of the above example program is:

Performing Deep Copy for Object initialization
true
false
ce id:10
ce name:original
ce testMap:{2=second, 1=first}
ce id after local variable change:10
ce name after local variable change:original
ce testMap after local variable change:{2=second, 1=first}
ce testMap after changing variable from accessor methods:{2=second, 1=first}

Why Deep Copy is important for immutability?

Let’s comment the constructor providing deep copy and uncomment the constructor providing a shallow copy. Also, uncomment the return statement in the getTestMap() method that returns the actual object reference. Run the program after all the changes are done. It will produce the following output.

Performing Shallow Copy for Object initialization
true
true
ce id:10
ce name:original
ce testMap:{2=second, 1=first}
ce id after local variable change:10
ce name after local variable change:original
ce testMap after local variable change:{3=third, 2=second, 1=first}
ce testMap after changing variable from accessor methods:{3=third, 2=second, 1=first, 4=new}

As you can see from the output, HashMap values got changed because of shallow copy in the constructor. It’s happening because of the direct reference to the original object in the getter function. That’s all for an immutable class in Java. We also learned the importance of deep copy for immutable classes. Further Reading: If the immutable class has a lot of attributes and some of them are optional, we can use builder pattern to create immutable classes.

You can check out more Java examples from our GitHub Repository.


Want to learn more? Join the DigitalOcean Community!

Join our DigitalOcean community of over a million developers for free! Get help and share knowledge in our Questions & Answers section, find tutorials and tools that will help you grow as a developer and scale your project or business, and subscribe to topics of interest.

Sign up
About the authors
Default avatar
Pankaj

author

Developer and author at DigitalOcean.

Still looking for an answer?

Was this helpful?

who can solve this for me? /* Edit the code by following the steps in the description */ import java.util.HashMap; import java.util.Map; public class Location { final int locationID; public String description; protected Map exits; public Location(int locationID, String description, Map exits) { this.locationID = locationID; this.description = description; this.exits = new HashMap(exits); this.exits.put(“Q”, 0); } public void addExit(String direction, int location) { exits.put(direction, location); } public void setLocationID(int locationID) { this.locationID = locationID; } public int getLocationID() { return locationID; } public void setDescription(String description) { this.description = description; } public String getDescription() { return description; } public void setExits(Map exits) { this.exits = exits; } public Map getExits() { return exits; } } Make the Location class an Immutable Class. The strategy for creating an Immutable Class is:     Steps:     1. Don’t provide setters.     2. Make all fields final and private     3. Don’t allow the class to be subclassed.     4. 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. As an added Task, handle the case where exits is null when passed to the constructor. NOTE: Not all classes documented as “immutable” follow these rules. However, the steps above are the basis of an Immutable Class.

- Francis

    I believe deep copy will be needed for ID and Name as well. Please explain if not.

    - Dinesh Solanki

      HI Pankaj, I tried your code and analysed that by only returning the map.clone() object will work here no need to make deep copy in constructor.

      - Lokesh Kumar

        Hi, its Explained very nicely, I have one question like i have 2 classes as below. class Separtment{ int id, String name; } Class Employee{ Department Dept, int id, String name; } Here i want to make Employee as immutable, but here Department is a child object, so here how come i make Employee class is immutable. Also One constraint like the Department object which I won’t own(I am not allowed to change anything in the Department object).

        - Akhil Kumar Patro

          hi Pankaj, great work !!! what is the need of getter method HashMap clone as we are constructing deep clone object? thanks Aravind Sundarraj

          - Aravind Sundarraj

            Hi Pankaj, I have been following your site for quite some time & it has been helping me a lot… Thank you very much for that. Just one suggestion, the “scrollable” code blocks are not very user-friendly to use. It would be great if we can see the entire code at once - even though it increases the height of the page, just my personal experience…

            - Shobhit Mittal

              What about Date variable we can still change the date by writing d.getTime(); How can we avoid that?

              - jogi

                4. Make all mutable fields final so that it’s value can be assigned only once. I don’t think this is necessary if are declaring the fields private. mutable fields marked as final can still be mutated, only the reference can not be changed.

                - Manohar Bhat

                  One of the best example and explanation for “creating immutable class”. Loved it. Thanks !!

                  - Mukund Padale

                    But when we trying to change a String object a new object would be created with those changes. Is that possible here ?. Please explain

                    - Sreerag