How to Create Immutable Class in java?

Filed Under: Java

Today we will learn how to create 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

Immutable Class in Java

immutable class in java, how to create immutable class in java, how to  make a class immutable

An immutable class is good for caching purpose because you don’t need to worry about the value changes. Other benefit of immutable class is that it is inherently thread-safe, so you don’t need 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 in Java via an example for better understanding.

To create an immutable class in java, you have to do 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 it’s 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 immutable class in java 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}

Now let’s comment the constructor providing deep copy and uncomment the constructor providing a shallow copy. Also uncomment the return statement in getTestMap() method that returns the actual object reference and then execute the program once again.


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 and providing a direct reference to the original object in the getter function.

That’s all for how to create an immutable class in java. If I have missed something here, feel free to comment.

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.

Comments

  1. jogi says:

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

    How can we avoid that?

  2. Manohar Bhat says:

    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.

  3. Mukund Padale says:

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

  4. Sreerag says:

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

  5. Ashwani Pratap says:

    What’s the significance of declaring class as final here?

    1. Pankaj says:

      So that it can’t be extended.

  6. Ravi Beli says:

    Even within this constructor if you assign cloned version of input “hm” to testMap, it should still work, no need of deep copy.
    public FinalClassExample(int i, String n, HashMap hm){
    System.out.println(“Performing Shallow Copy for Object initialization”);
    this.id=i;
    this.name=n;
    this.testMap=hm.clone();
    }

    1. Satish says:

      Perfect answer with a small change. You need to type cast when calling the clone method as it return object.

  7. Pandidurai says:

    Hi,

    First i want to thank you for sharing your knowledge with us.

    here i have one question with this

    if i am getting HashMap reference through getter method then i can avoid changing Immutable class value by sending deep copy. But what if user accessed it directly? i mean

    Map local = ce.testMap;

    local.put(“local” , “local”);

    in this case ce.testMap will have the above added object as well.

    How can we avoid this?

    thanks!

    1. Rishabh says:

      while returning map return new Object.

      So the getter method of testMap will look like getTestMap{
      return new HashMap(testMap);
      }

    2. vkas says:

      Hi Pandidurai , testMap access is private as rule, so you can not access outside class directly, without getter you can not access directly

  8. online java training says:

    It was worth a read about immutable class in Java! Really learned a lot form this article. I can imagine the effort you put into this & especially appreciate you sharing it. keep up the good work.

  9. Deepak says:

    Hi,
    please post your Java code of connection pooling in java without using Spring and hibernate.

  10. Parvise says:

    Not required map iteration in constructor and return statement clone which you used, may be any other reason please provide that.

    class Student {
    private final int sid;
    private final String sname;
    private final Map map;

    public Student(int sid, String sname, Map map) {
    super();
    this.sid = sid;
    this.sname = sname;
    this.map = new HashMap(map);
    //this.list=list;
    }

    public int getSid() {
    return sid;
    }

    public String getSname() {
    return sname;
    }

    public Map getList() {
    return map;
    }

    @Override
    public String toString() {
    return “Student [sid=” + sid + “, sname=” + sname + “]”;
    }

    }

    1. Pankaj says:

      Yes, we can use the HashMap constructor too. However, the idea here was to showcase how to perform the deep copy. Not every object constructor provides this feature, in that case, we need to perform field by field copy so that the original object and the cloned object have different references.

  11. u.mang says:

    This is how we create an immutable class. But can you please describe how the immutable object is created? or is that happens in java or not??

    1. Pankaj says:

      A class is a design and Object is the actual implementation. When we say immutable class, it means immutable objects too.

  12. Vijay Kumar says:

    Article is very nice and easy to understand. I have gone through the comments and got deeper understanding of this concept. Requesting everyone else to go through the discussions done in comments then you will get more understanding about this topic. Thanks to Pankaj.

  13. Omkar J says:

    Great Article…… very helpful in cracking interviews …. Thank you so much !!

  14. Jitendra Singh says:

    Hi Pankaj,

    Thanks for writing such an informative article.

    I would like to know what if my all member variables are immutable like all Strings or Wrappers?, Do I still need to follow above steps?

    Thanks,

    1. Pankaj says:

      Yes, most of them. You can get rid of deep-copy logic if the variables are immutable.

  15. Prahlad Kumar says:

    Hi Pankaj,

    What will happen if we do not declare class as final, since member variables are privare so can not be extendable.

    I am here trying to understand why we need final for class and its member variable.
    Is there any way state of a class can be modified if we don’t declare class and its variables final?

    Thanks,
    Prahlad.

    1. Gunjal Shrivastava says:

      You need the class as final so, that it cannot be extended further and it’s implememtation should not be changed by overriding the methods and by creating new variables.

      Making variables as final will make sure two things,
      1. Compiler will flag error if any reassignment will take place

      2. It will give readability to the code to other people who are working on the same class that these variables are not supposed to be changed. Basically it is because of IMHO

  16. Hagos haile says:

    correct output is:

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

    1. Vigilante says:

      Yeah Thats what i was thinking

      .ce testMap after changing variable from accessor methods:{1=first, 2=second, 3=third}

      4=new wont be get added

  17. TEJENDRA PRATAP SINGH says:

    Your getter method for HashMap can be in that way
    public HashMap getTestMap() {
    //return testMap;
    //HashMap tempMap=new HashMap();

    return new HashMap(testMap);
    }

  18. Vaibhav Jetly says:

    What if we remove the final access modifier from class as we are independently handling all the fields or methods of this class. And if some one extend this class then they doesn’t impact this class instance. Please suggest.

    1. Mike New says:

      But then it is circumventing the intent of the class.

      If you want additional behavior from a different class, create a different class and have the immutable one as an instance member of that class.

  19. Sameera says:

    I also wrote an article with a complete different view and you may have a look,

    http://www.codedjava.com/2017/09/immutable-objects-in-java_50.html

    Thanks,

  20. kuldeep patil says:

    I am not clear on Point 5 initialization

    swallow or Deep are comparison not initialization.
    swallow comparison is done by == and Deep comparison by equal / equalignorecase

    Did you mean initialization should be done at constructor with safer way without exposing identity of the fields?

  21. Rushabh says:

    Correct output is::
    Performing Shallow 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:{3=third, 2=second, 1=first}
    ce testMap after changing variable from accessor methods:{3=third, 2=second, 1=f
    irst}

  22. Tanmai says:

    Which Java version ? or forgot the Final variables initialisation?

    1. Manoj Kumar Vohra says:

      Final variables can be left uninitialized in declaration if initialization is provided by constructor.

  23. Anbu says:

    Hi setter method for map provides shallow copy only though clone method so that we can change the value later. How come you can say its immutable ?

    1. Prakash says:

      I believe, you are talking about getter method.

      public HashMap getTestMap() {
      //return testMap;
      return (HashMap) testMap.clone();
      }

      I believe, It should return a copy by deep cloning.

      1. Prakash says:

        I believe, In this example, Shallow copy would also work fine as long as we are storing immutable String object in HashMap.

        In case, if we need to store mutable object in HashMap. We should do deep cloning

  24. Pratyush says:

    I it necessary to have variable as final??
    We can achive it without it also,
    there is no statement to change varable.

  25. Rahul says:

    When you make the field final, Why making the variable private is mandate?

  26. tabish says:

    hi pankaj,

    i love to read your blog. here i found a hack at main() using a reflection how to prevent it.

    Class mc = ce.getClass();
    Field fs = mc.getDeclaredField(“name”);

    fs.setAccessible(true);

    fs.set(ce, “hacked”);

    System.out.println(“ce name after reflection hack:”+ce.getName());

    1. shashank says:

      You cannot do this since name is final

      1. Umang Gupta says:

        It does work.

  27. WAA says:

    Hi Pankaj
    I didn’t Understood the System.out.println(h1 == ce.getTestMap()) answer is False.
    Can you Please explain why it is false.

    1. Ankush K says:

      On this statement we are just checking the reference of h1 is pointing to the one that of our final class TestMap reference, which in this case is no, because we have made a new copy of h1 hashmap and copied it in TempHashMap which is an completely new Object, & then the reference of this temp map is assign to TestHashMap.

      Hence this reference are pointing to, two different Object all together.

  28. Bektur Toktosunov says:

    Thanks for great article!

    Can we use testMap.clone() in the constructor instead of going through all of the map items with Iterator?

  29. Vineet kaushik says:

    Very easy to understand and useful post!!

  30. Vijay Nandwana says:

    Thank you Pankaj. I’m a big fan of your writing skills. You cover every details and explain concepts in easy to understand language. Thanks again.

  31. Ajaz says:

    private final String name; …Why this is final …String is already final …do we need to declare it again..???

    1. Vinay says:

      “String is already final.” – yes , it is , but that final is at class level which means you can’t extend the String class, while that “private final String ” is for variable , so that we cant change the value of that object once initialized.

  32. Bijoy says:

    I can modify the object using ce.testMap.put(“10”, “ten”);

    Output:

    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, 10=ten}
    ce testMap after changing variable from accessor methods:{2=second, 1=first, 10=ten}

    1. parasuram tanguturu says:

      how to overcome this case;
      ce.testMap.put(“10”, “ten”);

      //ce testMap after local variable change:{2=second, 1=first, 10=ten}
      //ce testMap after changing variable from accessor methods:{2=second, 1=first, 10=ten}

      1. JavaRocker says:

        testMap is private variable and out side class it wont be available.

        Its just a Example code that is why in main you are able to do ce.testMap but in real application you wont be as generally you dont do such operations in POJO class.

  33. ahmed says:

    thanx
    i disable ABP for u

    1. Pankaj says:

      Thanks Ahmed, I appreciate it.

  34. S says:

    Excellent post!!

  35. mahi says:

    Can you please describe no 6. more deeply.I am not able to understand it.

  36. Rais Alam says:

    Hi Pankaj,

    It was a great learning about creating Immutable objects.If you are performing step 5 and 6 then step 4 is not required I guess. You are not storing or returning original reference of HashMap, You are using clone concept for that, Hence as a result client application have no way to reassign new object to declared HaspMap.

    Please correct me If I am missing some thing

    Thanks& Regards
    Rais Alam

  37. Ramakant says:

    Should not be String name declared as a not final? Its not mutable anyway.

  38. Marwen says:

    Thanks for the detailed tutorial, well written and the flow goes exactely to showing up almost the need of every instruction in the code 🙂
    One side question, even if I know we are talking about Objects immutability,but what about the other instance variables you introucted in the FinalClassExample (id, name)?
    Is there any way to make them immutable?

    1. Pankaj says:

      int and String both are already immutable, since there are no setter methods for them. For any other class variables, you should return a deep copy of the variable to avoid mutability.

  39. Mirey says:

    Thanks, you know it and you know how to explain it too! I will definitely read more of your articles 🙂

  40. Anish Sneh says:

    Thanks mate, great details..

    — Anish Sneh

    1. Pankaj says:

      Thanks for the kind words.

  41. Łomża Zuhlke says:

    It’s super webpage, I was looking for something like this

  42. whaley says:

    Out of curiosity, why the requirement to have the class be marked as final so as not to be extended? What does disallowing subclasses actually provide in terms of allowing objects of this type to be immutable?

    Further, you don’t have to mark fields as private only just so long as you can guarantee that all constructor’s of the class properly initialize all of the fields.

    As a side note, you *can* have setters, but with the nuance that instead of changing an internal field, what the setter really does is specify a return type of the class the method is on, and then behind the scenes creates a new object using a constructor that accepts all internal fields, using the internally held state in for all params with the exception of the field represented by the setter called since you want the new object to have that field updated.

    1. Pankaj says:

      If the class is not marked as final then its function can be overridden in the subclass either accidentally or intentionally. So its more related to keep the object secure. For this either all the getter methods can be made final or the class itself – this is again a design decision and depends on the requirement.

      Again if the fields wont be private then client application can override the value. Make the HashMap as public in the code and run the below code to see yourself.

      FinalClassExample fce = new FinalClassExample(1,"", new HashMap());
      System.out.println(fce.testMap);
      HashMap
      hm = fce.testMap;
      hm.put("1", "1");
      System.out.println(fce.testMap);

      Having a setter function will give the feeling that the actual object has been modified whereas internally creating a new object. Its better to client application know that its immutable (like String).

  43. In Groovy you can annotate the class as @Immutable and get /almost/ similar results to the scala example without all the boilerplate. IMHO Scala is better for it’s immutable support though.

    Also, don’t forget that Java Date, Dimension, and other JDK classes are not immutable as well, so you need to make defensive copies of those classes as well.

    1. Pankaj says:

      Exactly, for all the mutable objects we need to return the defensive copy rather than same object reference.
      Have to dig into Scala now.

  44. John says:

    why don’t you just do this:

    import static java.util.Collections.unmodifiableMap;

    public final class FinalClassExample {

    ...

    private final Map testMap;

    public FinalClassExample(int i, String n, Map m){
    id = i;
    name = n;
    testMap = unmodifiableMap(new HashMap (m));
    }

    public Map getTestMap() {
    return testMap;
    }

    ...
    }

    1. Pankaj says:

      In this case, when we will get the testMap from getTestMap() function, we will not be allowed to modify it and it will throw exception. Also in that case again we are passing the reference and the values will change accordingly.
      Try executing this class:

      package com.journeldev.java;

      import static java.util.Collections.unmodifiableMap;

      import java.util.HashMap;
      import java.util.Map;

      public final class FinalClassExample1 {

      private final Map testMap;

      public Map getTestMap() {
      return testMap;
      }

      public FinalClassExample1(Map hm) {
      this.testMap = unmodifiableMap(hm);
      }

      public static void main(String[] args) {
      HashMap h1 = new HashMap();
      h1.put("1", "first");
      h1.put("2", "second");
      FinalClassExample1 ce = new FinalClassExample1(h1);
      System.out.println("ce testMap:" + ce.getTestMap());
      h1.put("3", "third");
      System.out.println("ce testMap after local variable change:"+ ce.getTestMap());
      Map hmTest = ce.getTestMap();
      hmTest.put("4", "new");
      System.out.println("ce testMap after changing variable from accessor methods:"+ ce.getTestMap());

      }

      }

      Output will be:
      ce testMap:{2=second, 1=first}
      ce testMap after local variable change:{3=third, 2=second, 1=first}
      Exception in thread “main” java.lang.UnsupportedOperationException
      at java.util.Collections$UnmodifiableMap.put(Collections.java:1285)
      at com.journeldev.java.FinalClassExample1.main(FinalClassExample1.java:33)

      1. Steve says:

        Pankaj,

        You should not be allowed to modify a map you get from getTestMap. Objects coming from an immutable object, I would expect to also be immutable so you can not change the internals of the object after it is created. A mutable map may imply that the objects map is changed. Sure you can document that the object returned is new, but being defensive upfront seems better.

        Another alternative is to never return collections. Instead, define a forEach method that takes a function:

        public void forEach(Function fn) {
        for(Thing t : Iterable collection) {
        fn.apply(t);
        }
        }

        1. Pankaj says:

          I am not sure why the map returned from getTestMap method should not be allowed to modify. Suppose the list contains some 1000 items and client wants to add 5 more to make their own immutable object instance, in this case its better to let them modify the returned object and do whatever they want on it.
          Usually, we have setter methods to change the state of object, so just by changing the returned object you should not think that the object state has been changed because the internal implementation is not known to us(as a client).

      2. John says:

        you didn’t notice that I wrote:

        this.testMap = modifiableMap(new HashMap (m))

        so you couldn't change the inner map after construction.

        and I agree with Steve that the map returned by getTestMap() should not be modifiable as this would give the false impression that you're actually changing the immutable object.

        in that case I would prefer doing something like this:

        FinalClassExample example = new FinalClassExample(...);
        Map newMap = new HashMap(example.getTestMap());
        newMap.put("hello", "world");

        1. Pankaj says:

          Ok agreed that this will work but then its not generic. What if its some generic mutable class like Date or may be user defined class where you don’t have this feature. This example is intended to provide a generic way to create immutable classes.

          As for changing the object state, that is why we have setter methods and I still prefer it doing like that… but again it depends on your application requirements and design.

  45. Shouldn’t it be “shallow copy” instead of “swallow copy” unless I am missing something?

    1. Pankaj says:

      Thanks for pointing out the typo error. Corrected now to shallow copy.

  46. Ken says:

    … and here is a translation of the entire exercise into Scala, except without the wasteful copying and cloning, and with correct equals and hashCode methods:

    case class FinalClassExample(id: Int, name: String, testMap: Map[String,String])

    1. Pankaj says:

      I didn’t understood what are you trying to point here?

      1. Paweł Chłopek says:

        I belive that he was trying to point out that Scala lets you create immutable classes in more concise way. I’m new to Scala myself and already I love and often use these one liners. Less code less opportunities to make mistakes 🙂

        1. Pankaj says:

          Thats a completely new thing to me… Got something new to learn now… will dig into this soon 🙂

Leave a Reply

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

close
Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages