In Java, an immutable object is one whose state can not be changed once created. Immutable objects are persistent views of their data without a direct option to change it. To change the state, we must create a new copy of such an object with the intended changes.
In this post, we will learn immutability in detail, creating an immutable object and its advantages.
1. What is Immutability?
Immutability is a characteristic of Java objects that makes them immutable to future changes once they have been initialized. Its internal state cannot be changed in any way.
Take the example of java.lang.String class which is an immutable class. Once a String is created, there is no way we can change the content of that String. Every public API in String class returns a new String with the modified content. The original String always remains the same.
String string = "test";
String newString = string.toLowerCase(); //Creates a new String
2. Immutability in Collections
Similarly, for Collections, Java provides a certain degree of immutability with three options:
- Unmodifiable collections
- Immutable collection factory methods (Java 9+)
- Immutable copies (Java 10+)
Collections.unmodifiableList(recordList); //Unmodifiable list
List.of(new Record(1, "test")); //Factory methods in Java 9
List.copyOf(recordList); //Java 10
Note that such collections are only shallowly immutable, meaning that we can not add or remove any elements, but the collection elements themselves aren’t guaranteed to be immutable. If we hold the reference of a collection element, then we can change the element’s state without affecting the collection.
In the following example, we cannot add or remove the list items, but we can change the state of an existing item in the list.
List<Record> list = List.of(new Record(1, "value"));
System.out.println(list); //[Record(id=1, name=value)]
//list.add(new Record()); //UnsupportedOperationException
list.get(0).setName("modified-value");
System.out.println(list); //[Record(id=1, name=modified-value)]
@Data
@NoArgsConstructor
@AllArgsConstructor
class Record {
long id;
String name;
}
To ensure complete immutability, we must make sure that we only add immutable instances in the collections. This way, even if somebody gets a reference to an item in the collection, it cannot change anything.
3. How to Create an Immutable Class?
Java documentation itself has some guidelines identified to write immutable classes in this link. We will understand what these guidelines actually mean.
- Do not provide setter methods. Setter methods are meant to change an object’s state, which we want to prevent here.
- Make all fields final and private. Fields declared private will not be accessible outside the class, and making them final will ensure that we can not change them even accidentally.
- Do not allow subclasses to override methods. The easiest way is to declare the class as final. Final classes in Java can not be extended.
- Special attention to “immutable classes with mutable fields“. Always remember that member fields will be either mutable or immutable. Values of immutable members (primitives, wrapper classes, String etc) can be returned safely from the getter methods. For mutable members (POJO, collections etc), we must copy the content into a new Object before returning from the getter method.
Let us apply all the above rules to create an immutable custom class. Notice that we are returning a new copy of ArrayList from the getTokens() method. By doing so, we are hiding the original tokens list so no one can even get a reference of it and change it.
final class Record {
private final long id;
private final String name;
private final List<String> tokens;
public Record(long id, String name, List<String> tokens) {
this.id = id;
this.name = name;
this.tokens = tokens;
}
public long getId() {
return id;
}
public String getName() {
return name;
}
public List<String> getTokens() {
return new ArrayList<>(tokens);
}
@Override
public String toString() {
return "Record{" +
"id=" + id +
", name='" + name + '\'' +
", tokens=" + tokens +
'}';
}
}
Now it’s time to test our class. We tried to add a new item to the tokens list, but the original record and its list remain unchanged.
ArrayList<String> tokens = new ArrayList<>();
tokens.add("active");
Record record = new Record(1, "value", tokens);
System.out.println(record); //Record{id=1, name='value', tokens=[active]}
record.getTokens().add("new token");
System.out.println(record); //Record{id=1, name='value', tokens=[active]}
4. Immutability with Java Records
Java records help reduce the boilerplate code by generating the constructors and getters at compile time. They can also help create immutable classes with very few lines of code.
For example, we can rewrite the above Record class as follows. Note that records generate the standard getters, so if we want to return a new copy of a mutable reference, we must override the corresponding method.
record Record(long id, String name, List<String> tokens){
public List<String> tokens() {
return new ArrayList<>(tokens);
}
}
Now let us test the immutability again.
ArrayList<String> tokens = new ArrayList<>();
tokens.add("active");
Record record = new Record(1, "value", tokens);
System.out.println(record); //Record{id=1, name='value', tokens=[active]}
record.tokens().add("new token");
System.out.println(record); ////Record{id=1, name='value', tokens=[active]}
5. Immutable Classes in JDK
Apart from your written classes, JDK itself has lots of immutable classes. Given is such a list of immutable classes in Java.
- java.lang.String
- Wrapper classes such as Integer, Long, Double etc
- java.math.BigInteger and java.math.BigDecimal
- Unmodifiable collections such as Collections.singletonMap()
- java.lang.StackTraceElement
- Java enums
- java.util.Locale
- java.util.UUID
- Java 8 Date Time API – LocalDate, LocalTime etc.
- record types
6. Advantages
Immutable objects provide a lot of advantages over mutable objects. Let us discuss them.
- Predictability: guarantees that objects won’t change due to coding mistakes or by 3rd party libraries. As long as we reference a data structure, we know it is the same as at the time of its creation.
- Validity: is not needed to be tested again and again. Once we create the immutable object and test its validity once, we know that it will be valid indefinitely.
- Thread-safety: is achieved in the program as no thread can change immutable objects. It helps in writing code in a simple manner without accidentally corrupting the shared data objects.
- Cacheability: can be applied to immutable objects without worrying about state changes in the future. Optimization techniques, like memoization, are only possible with immutable data structures.
7. Conclusion
This tutorial taught us to create an immutable java class with mutable objects and immutable fields.
In Java, immutable classes are:
- are simple to construct, test, and use
- are automatically thread-safe and have no synchronization issues
- do not need a copy constructor
- do not need an implementation of clone()
- allow
hashCode()to use lazy initialization, and to cache its return value - do not need to be copied defensively when used as a field
- make good Map keys and Set elements (these objects must not change state while in the collection)
- have their class invariant established once upon construction, and it never needs to be checked again
- always have “failure atomicity” (a term used by Joshua Bloch) : if an immutable object throws an exception, it’s never left in an undesirable or indeterminate state
We also saw the benefits which immutable classes bring in an application. As a design best practice, always aim to make your application Java classes to be immutable. In this way, you can always worry less about concurrency related defects in your program.
Happy Learning!!
I have two doubts regarding this immutability example.
(1) Why you are creating new Date objects at two places: one in constructor and other one in getMutableField() method? If I simply do this.mutableField = date.getTime() in constructor and in getMutableField() return new Date() instance , then the output remains same . Means still object is immutable
(2) Also the hashcode of all new Date object in your code is same if you print it. Means any change in the object is going to be reflected everywhere. So does it ensures immutability?
Hi Nishant, thanks for sharing your thoughts.
1) Any implementation is good as far as you don’t break the immutability. I really don’t understand your first point. Probably you can share the code.
2) Hash code only comes into scene when you start using it as key in maps. And this is never my intention.
final class Immutable { private final int a; private final String s; private final Chirag ss; public Immutable (int a1, String s1, Chirag ss1){ this.a = a1; this.s = s1; this.ss = ss1; } public Integer geta() { return a; } public String gets() { return s; } public String toString() { return a + " - " + s + " - " + ss.age; } private static void modification(int a2, String s2, Chirag ss2){ a2 = 20; ss2.age = 11; s2 = "changed"; } public static void main(String[] args){ Immutable im = new Immutable(14, "age", new Chirag(20)); System.out.println(im); modification(im.a, im.s, im.ss); System.out.println(im); } } class Chirag { public int age; Chirag(int s) { this.age = s; } }Output: 14 - age - 20 14 - age - 11What do i do so that the ss.age value does not change?
package com.cic.testcase; public class MyImmutable { private final Integer a; private final String s; private final Demo ss; private MyImmutable(int a1, String s1, Demo ss1) { this.a = a1; this.s = s1; this.ss = new Demo(ss1.getAge()); } // factory method for obj creation public static MyImmutable newInstance(int a1, String s1, Demo ss1) { return new MyImmutable(a1, s1, ss1); } public Integer getA() { return a; } public String getS() { return s; } public Demo getSs() { return new Demo(ss.getAge()); } @Override public String toString() { return "MyImmutable [a=" + a + ", s=" + s + ", ss=" + ss + "]"; } } package com.cic.testcase; public class Demo { public int age; Demo(int s) { this.age = s; } int getAge() { return age; } @Override public String toString() { return "Demo [age=" + age + "]"; } } package com.cic.testcase; public class Test { public static void main(String[] args){ MyImmutable im = MyImmutable.newInstance(14, "age", new Demo(20)); System.out.println(im); modification(im.getA(), im.getS(), im.getSs()); System.out.println(im); } private static void modification(int a2, String s2, Demo ss2){ a2 = 20; ss2.age = 11; s2 = "changed"; } }OUTPUT:
MyImmutable [a=14, s=age, ss=Demo [age=20]]
MyImmutable [a=14, s=age, ss=Demo [age=20]]
Hello Lokesh
please explain memory management in java and java class loading system these topics are so confusing.
Could please paste some sample code to make a list field immutable
private List mutateList;
List unmodifiableList = Collections.unmodifiableList(list); Return unmodifiableList;Date class is mutable so we need a little care here.
* We should not return the reference of original instance variable.
* Instead a new Date object, with content copied to it, should be returned.
* */
public Date getMutableField() {
return new Date(mutableField.getTime());
}
Why we need new Date object for mutable field?
How new Date(mutableField.getTime()) is different from mutableField.getTime();
It’s about
new Date(mutableField.getTime()).setTime()andmutableField.setTime(). You see the difference? In first way, mutableField will not change, second way it will change.Because we don’t want to “leak” the reference of original date object to prevent any modification on it.
Hi
Can’t i create a class immutable by not using final at all ?
For eg :-
1. make the constructor private & all all variables private
2. Now make a public method createInstance() which returns new object of the class
Is this class not immutable ?
correct me if i am wrong …
Thanks
Karan
Hi Karan, yes it’s possible to achieve immutability by your approach as well. In fact, there is no MUST DO guidelines for this.
Think after get the final Date instance, if I call setTime to change value.
Hi guys,
First of all, this is interesting article, but I get stuck at one point, it is: “A more sophisticated approach is to make the constructor private and construct instances in factory methods.”. If I declare the constructor with 3 parameters is public (don’t have createNewInstance method), I think it’s still immutable class, if not, could you give me an example to prove my fault, please?
Thanks in advance.
Cuong.
Yes, it will be immutable class. “Making constructor private” is not mandatory requirement.
public final class ImmutableClass { private final Integer immutableField1; private final String immutableField2; /** * Date class is mutable so we need a little care here. * We should not return the reference of original instance variable. * Instead a new Date object, with content copied to it, should be returned. * */ private Date mutableField; // I did not put final here public ImmutableClass(Integer field1, String field2, Date date){ this.immutableField1 = field1; this.immutableField2 = field2; //this is very important else what would happen is if we change the reference, then all will change this.mutableField = new Date(date.getTime()); } public Integer getIntImmutableField(){ return immutableField1; } public String getStringImmutableField(){ return immutableField2; } public Date getMutableField(){ return mutableField; } }MAIN class
——————-
public class App { public static void main(String[] args) throws ParseException { ImmutableClass immutableClass = new ImmutableClass(100,"test", new Date()); Integer intTest = immutableClass.getIntImmutableField(); Date date = immutableClass.getMutableField(); System.out.println("Date associated with object:"+date); SimpleDateFormat sdf = new SimpleDateFormat("dd-M-yyyy hh:mm:ss"); String dateInString = "31-08-1982 10:20:56"; date = sdf.parse(dateInString); System.out.println("New Date:"+date); System.out.println("Date associated with object:"+immutableClass.getMutableField()); } }As you can see that I have removed final modifier from Date object which is mutable by default. But even after that when I try to get the reference of date from object and modify the date, I am not able to do it. Any idea why this is happening ?
You are not changing the date. Rather you are assigning the reference of new date object to a local date reference (not of date object inside immutable class). Try this:
Integer is immutable because it does not provide any setter method – so even if you have it’s reference you cannot change the content. Date class provide setter methods – so it’s mutable.
Hi lokesh,
I have couple of question in regards to the Immutabilty. Please see if you can help out-
If I don’t follow the sophisticated approach of writing a private constructor/any constructor and just write the code using first 4 points (I mean not at all writing any constructor) and an object of Immutable class in made by using the default constructor, Then
A. How will Immutabilty of the class be maintained as the values of properties are not set anywhere?
Can you explain the following code.
public final class TestImmutable {
private final String test;
private final String test1;
private final Date dd;
TestImmutable(String s, String t, Date dd){
this.test=s;
this.test1=t;
this.dd=dd;
}
public String getTest() {
return test;
}
public String getTest1() {
return test1;
}
public Date getDd() {
return dd;
}
@Override
public String toString(){
return test+”–“+test1+”–“+dd;
}
}
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
TestImmutable ti=new TestImmutable(“subose”, “chandra”, new Date());
System.out.println(ti);
Date dd=ti.getDd();
String s=ti.getTest1();
s=”Gaddala”;
dd.setDate(10);
System.out.println(ti); // Date get Changed
}
}
String in immutable class but Date is mutable class. You should return a new date object from
getDd()method, that will prevent the original date being changed.Actually @Shruti want to say that if a Class contain a List.
Then how you make it immutable ?
Ex :
public final class ImmutableClass
{
Private final List c1;
}
So in this case, you must return the list instance wrapped in Collections.unmodifiableList() from it’s getter method.
Hi Lokesh, I have a question – As you mention, I made my constructor as private and provided a factory method which gives me instance of class
private final String name;
private final int id;
private final Integer doorId;
private final Date dateOfJoining;
public static ImmutablePOJO getObject(String name,int id, Integer doorId,Date dateOfJoining) {
// TODO Auto-generated method stub
return new ImmutablePOJO(name, id, doorId, dateOfJoining);
}
private ImmutablePOJO( String name,int id, Integer doorId,Date dateOfJoining){
this.name=name;
this.id=id;
this.doorId=doorId;
//this.dateOfJoining=dateOfJoining;
this.dateOfJoining=new Date(dateOfJoining.getTime());
}
public Date getDateOfJoining() {
//Below line of code will allow to modify the mutable fields
return dateOfJoining;
//This piece of code helps us in maintaining the same value for mutable field
//return new Date(dateOfJoining.getTime());
}
public static void main(String[] args) {
// TODO Auto-generated method stub
ImmutablePOJO immutablePOJO= ImmutablePOJO.getObject(“memosha”, 100, 100, new Date());
System.out.println(“Before calling to the method to change the value “);
System.out.println(immutablePOJO.toString());
//Call the method to change the vale and see the effect
changeValue(immutablePOJO.getDateOfJoining());
System.out.println(immutablePOJO.toString());
}
public static void changeValue(Date dateOfJoining){
//So the value of mutable field is changing if we pass the direct reference
dateOfJoining.setDate(10);
}
Still I am able to change the value of Date dateOfJoining
Comment out – return dateOfJoining;
Uncomment this – //return new Date(dateOfJoining.getTime());
private final String name;
private final int id;
private final Integer doorId;
private final Date dateOfJoining;
private Student(String name,int id, Integer doorId,Date dateOfJoining){
this.name=name;
this.id=id;
this.doorId=doorId;
//this.dateOfJoining=dateOfJoining;
this.dateOfJoining=new Date(dateOfJoining.getTime());
}
public static Student getObject(String name,int id, Integer doorId,Date dateOfJoining) {
// TODO Auto-generated method stub
return new Student(name, id, doorId, dateOfJoining);
}
When I call the below statements still I am able to change the value
public static void main(String[] args) {
// TODO Auto-generated method stub
Student student= Student.getObject(“memosha”, 100, 100, new Date());
System.out.println(“Before calling to the method to change the value “);
System.out.println(student.toString());
//Call the method to change the vale and see the effect
changeValue(student.getDateOfJoining());
System.out.println(student.toString());
}
public static void changeValue(Date dateOfJoining){
//So the value of mutable field is changing if we pass the direct reference
dateOfJoining.setDate(1000);
}
Before calling to the method to change the value
name =memosha ,id =100, doorId100, dateOfJoiningThu Jan 14 12:31:43 IST 2016
After calling the method
name =memosha ,id =100, doorId100, dateOfJoiningWed Sep 26 12:31:43 IST 2018.
Please verify and explain me this.
Why class is declared as final.
If all variables are private, even if class is extended , variables are not visible to in derived class.
Also no need to declare variables are final, private is enough.
Making class final is necessary because one can create a mutable subclass and inject it’s reference to main immutable class. Application will be compromised in this way.
Next thing, even if variables are not visible in subclass, yet getter methods are. You can easily override the getter method, inject its reference in super class and blow up whole immutability based design.
Making variables final is optional but certainly highly recommended. You do not want to change the state of object in any way, after it’s fully initialized. private prevent changing them in other classes, but final ensures that you will not be able to change even inside same class also.
Hi,
I have doubt on this. If variables in class are final, and we mark all the methods also final, what’s the need of marking class as final. Please tell.
Hi Lokesh,
In TestMain.tryModification(…) this has local variables whose scope is within in this method, any fool will understand that you are modifying content of local parameters, how would your test case confirms you that you are trying to modify ImmutableClass instances???
Hi Ravi, Could you please try some modifications and share with all of us your findings?? Let me know if something interesting you find.
Why is it we need a “Private Constructor” in an immutable class? What is the specific need of it?
Absolutely no need. As far as you are able to create a fully initialized instance of class, and does not let modify users to change it after, you are free to make it public as well.
let’s say we have a constructor for immutable class, which takes in 2 parameters: String1 and String2. Now after calling the constructor from main method, we modify those strings that were initially passed in the constructor, then wouldn’t it impact our immutable class object instance?
Nope String is itself immutable so changing string1 and string2 would not change the values in the Immutable class Instance variable say immutableString1 and immutableString2. Even more to say it would be pointing to a different location in the String pool.
That is : let us say:
string1 = “hi”; //lets us say in memmory where ultimately it would be stored – 33450
string2 = “Vinay”; // lets us say in memmory where ultimately it would be stored – 33451
now let us say you pass this values to the constructor using new Immutable(string1, string2);
now lets say after assigning in the constructor:
immutableString1 and string1 point to 33450 location in pool with Value as hi
immutableString2 and string2 point to 33451 location in pool with Value as Vinay
Now if you change
string1 = “bye”;//would point to a new location in memmory 33452 as bye
string2 = “Rahul”;//would point to a new location in memmory 33453 as Rahul
The values in memmory 33450 and 33451 remains untouched because of which immutableString1 and immutableString2 would not be changed. That is why cloning was not necessary for Immutable instance variable but if you try the same with date without cloning you would run into problems.
So even I feel private constructor is not actually needed.
I don’t get it..!! How can one assign value to final declared variable/object ?? for example. private final Integer int; it give error here itself !!
ohh sorry, I got it.. we are initializing it from constructor. Can you please explain about following scenario:
//..... Case 1.... private final int num; public Constructor(int num) { this.num =num; // this is working } //......Case 2... private final static int num; public Constructor(int num) { this.num = num; // not working }static variables/blocks are initialized even before constructor is called. Also, static variables can be accesses only inside static blocks.
Hi,
The keyword ‘this’ refers to current instance. but ‘static’ is not specific to any instance, so that the below code never works.
private final static int num;
public Constructor(int num)
{
this.num = num; // not working
}
if you create a variable static final it means your variable is constant it means you can not change the value of your static final variable.
The simplest way to do this is to declare the class as final. Final classes in java can not be overridden.
i mean ….the correct thing should be final classes cannot be subclasses and final methods cannot be overridden in a subclass
OK. But how it make a class immutable? I can still change the state of class by changing the values of fields it contain.
Hi Lokesh,
When you change the values of the fields the state does not change but, the new object of that class will be created and its reference points to the new object (while old object is still in memory).
Thanks,
Raveesh
Hi Raveesh,
I am not sure if I get your question. But instance variable define the state of the object. So when somebody says a class is immutable it means once defined nobody can change its state which means that nobody can change its instance variables.
So If an Raveesh object of class Employee is created then its instance variable name cannot be changed to Vinay.
Unless a new object with Vinay is created. So if multiple threads are accessing Raveesh object, no one can come in and suddenly change its state to Vinay shocking all the other threads.
Hope it is clear now.
Hi, in below code if i have 100 variables and getter and setter for this am i supposed to add them manually in getT() method is there any shortcut
package Immutable2; import java.util.Date; /** * Always remember that your instance variables will be either mutable or immutable. * Identify them and return new objects with copied content for all mutable objects. * Immutable variables can be returned safely without extra effort. * */ public final class ImmutableClass { /** * Integer class is immutable as it does not provide any setter to change its content * */ private final Integer immutableField1; /** * String class is immutable as it also does not provide setter to change its content * */ private final String immutableField2; /** * Date class is mutable as it provide setters to change various date/time parts * */ private final Date mutableField; private final Test t; //Default private constructor will ensure no unplanned construction of class private ImmutableClass(Integer fld1, String fld2, Date date, Test t) { this.immutableField1 = fld1; this.immutableField2 = fld2; Date d = new Date(); d.setTime(date.getTime()); //this.mutableField = new Date(date.getTime()); this.mutableField = d; Test tt = new Test(); tt.setName(t.getName()); this.t = tt; } //Factory method to store object creation logic in single place public static ImmutableClass createNewInstance(Integer fld1, String fld2, Date date, Test t) { return new ImmutableClass(fld1, fld2, date, t); } //Provide no setter methods /** * Integer class is immutable so we can return the instance variable as it is * */ public Integer getImmutableField1() { return immutableField1; } /** * String class is also immutable so we can return the instance variable as it is * */ public String getImmutableField2() { return immutableField2; } /** * Date class is mutable so we need a little care here. * We should not return the reference of original instance variable. * Instead a new Date object, with content copied to it, should be returned. * */ public Date getMutableField() { return new Date(mutableField.getTime()); } public Test getT() { Test t1 = new Test(); t1.setName(t.getName()); return t1; // return new Test(); } @Override public String toString() { return immutableField1 + " – " + immutableField2 + " – " + mutableField + "-" + t.getName(); } public static void main(String[] args) { Test t = new Test(); t.setName("kiran"); Date d = new Date(); d.setTime(100000000); ImmutableClass im = ImmutableClass.createNewInstance(100, "test", d, t); System.out.println(im); tryModification(im.getImmutableField1(), im.getImmutableField2(), im.getMutableField(), im.getT()); System.out.println(im.getT().getName()); System.out.println(im); } private static void tryModification(Integer immutableField1, String immutableField2, Date mutableField, Test t) { immutableField1 = 10000; immutableField2 = "test changed"; mutableField.setDate(10); t.setName("uday"); } } class Test { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }You can use BeanUtils.copyProperties() method
Hi Lokesh,
Could you please explain me in brief? why the below code is not showing immutable behaviour as you explain above….
infact i have modified your code and included one mutable class Test with an attribute name with setter and getter method for name…I did it in the same way as you did for mutable class Date but output you can verify below.
package com.barun; import java.util.Date; /** * Always remember that your instance variables will be either mutable or immutable. * Identify them and return new objects with copied content for all mutable objects. * Immutable variables can be returned safely without extra effort. * */ public final class ImmutableClass { /** * Integer class is immutable as it does not provide any setter to change its content * */ private final Integer immutableField1; /** * String class is immutable as it also does not provide setter to change its content * */ private final String immutableField2; /** * Date class is mutable as it provide setters to change various date/time parts * */ private final Date mutableField; private final Test t; //Default private constructor will ensure no unplanned construction of class private ImmutableClass(Integer fld1, String fld2, Date date, Test t) { this.immutableField1 = fld1; this.immutableField2 = fld2; Date d = new Date(); d.setTime(date.getTime()); //this.mutableField = new Date(date.getTime()); this.mutableField = d; Test tt = new Test(); tt.setName(t.getName()); this.t = tt; } //Factory method to store object creation logic in single place public static ImmutableClass createNewInstance(Integer fld1, String fld2, Date date, Test t) { return new ImmutableClass(fld1, fld2, date, t); } //Provide no setter methods /** * Integer class is immutable so we can return the instance variable as it is * */ public Integer getImmutableField1() { return immutableField1; } /** * String class is also immutable so we can return the instance variable as it is * */ public String getImmutableField2() { return immutableField2; } /** * Date class is mutable so we need a little care here. * We should not return the reference of original instance variable. * Instead a new Date object, with content copied to it, should be returned. * */ public Date getMutableField() { return new Date(mutableField.getTime()); } public Test getT() { return t; } @Override public String toString() { return immutableField1 + " – " + immutableField2 + " – " + mutableField + "-" + t.getName(); } public static void main(String[] args) { Test t = new Test(); t.setName("barun"); Date d = new Date(); d.setTime(100000000); ImmutableClass im = ImmutableClass.createNewInstance(100, "test", d, t); System.out.println(im); tryModification(im.getImmutableField1(), im.getImmutableField2(), im.getMutableField(), im.getT()); System.out.println(im); } private static void tryModification(Integer immutableField1, String immutableField2, Date mutableField, Test t) { immutableField1 = 10000; immutableField2 = "test changed"; mutableField.setDate(10); t.setName("tarun"); } } class Test { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }For other’s information, the output of above code is:
100 – test – Fri Jan 02 09:16:40 IST 1970-barun
100 – test – Fri Jan 02 09:16:40 IST 1970-tarun
Barun, as you see the class is not immutable as you are able to change the name from “barun” to “tarun”. To understand this, you must know the concept that Java is pass by value [please read this post]. When you pass reference of t to method tryModification(), then there are two reference variables in program referring to same instance of Test. You can say e.g. t1 = t2 = new Test(); This also has two reference variable t1 and t2; both pointing to single instance of Test.
If you change anything in instance of Test by using reference of t1, then t2 will also be able to see it. Both referring to same instance, remember. Now what if you make t2 ‘null’ or assign any new instance of Test(). Will t1 impact?? NO. Assigning null or another instance make t2 to point somewhere else; but t1 is still pointing to original instance.
package test.core; public final class ImmutableClass { public static void main(String[] args) { Test t1 = new Test(); t1.setName(&amp;amp;amp;quot;barun&amp;amp;amp;quot;); Test t2 = t1; //Change the name t2.setName(&amp;amp;amp;quot;tarun&amp;amp;amp;quot;); System.out.println(t1.getName()); //Mak2 t2 null t2 = null; System.out.println(t1.getName()); //Mak2 t2 point to another instance t2 = new Test(); t2.setName(&amp;amp;amp;quot;lokesh&amp;amp;amp;quot;); System.out.println(t1.getName()); } } class Test { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } Output: tarun tarun tarunYou see why name value got changed, because reference of Test() got skipped outside ImmutableClass. Once you have reference of an object, you can always change it’s state if it’s mutable. Mutability of Test class, make ImmutableClass mutable as well.
To prevent this, you need to return a new instance of Test from getT(). This will ensure that original reference of Test() does not skip outside the ImmutableClass, so that nobody can change it.
Hope it helps.
Sir, I am a bit confused and would like to ask that whatever we are changing in the tryModification method, we are changing it locally to this method..then anyway its not going to reflect the changes in the class…so if I take any int variable in the class without keeping it final then also it won’t change as that int variable is changed locally….
Following is your code with little modification
package com.immutable.test;
import java.util.Date; public final class ImmutableClass { private final String name; private final Integer num; private final Date date; private int i; public ImmutableClass(String name,Integer num, Date date,int i){ this.name = name; this.num = num; this.date = new Date(date.getTime()); this.i = i; } public int getI(){ return i; } public String getName(){ return name; } public Integer getNum(){ return num; } public Date getDate() { return new Date(date.getTime()); } public String toString(){ return name+" "+num+" "+date+" and int number is-> "+i; } } package com.immutable.test; import java.util.Date; public class TestMain { public static void main(String[] args) { ImmutableClass immutableClass = new ImmutableClass("Rahul", 1012516, new Date(),21); System.out.println(immutableClass); modify(immutableClass.getName(), immutableClass.getNum(), immutableClass.getDate(),immutableClass.getI()); System.out.println(immutableClass); } @SuppressWarnings("deprecation") private static void modify(String name, Integer num,Date date,int i){ name = "Rocky"; num= 1012517; date.setDate(101); i = 11; } }Output : Rahul 1012516 Tue Jun 24 12:45:18 IST 2014 and int number is-> 21
Rahul 1012516 Tue Jun 24 12:45:18 IST 2014 and int number is-> 21
Sir,please clarify
Hi Rahul, Thanks for asking this question. Asking a question to clear doubt is always better, then remaining in doubt.
When you talk about immutability, always seperate fields in class into two sections: i.e. mutable fields and immutable fields.
All primitives (e.g. int, long), wrapper classes (e.g. Integer, Double) and String class are implicitly immutable in java so you do not need to much worry about it.
Date class is mutable field so you need to safeguard it with some extra code e.g. we wrote getDate like this:
public Date getDate() { return new Date(date.getTime()); }What we are actually returning a new copy of Date object, so is somebody manipulate it then original copy is unchanged.
Date class provides you setXXX() methods which allow changing it’s content. Primitives and Wrapper classes do not provide any set methods, so you can’t change anything inside them.
You are tight that methods receive a local copy to work on, but that copy is actually a copy of reference pointing to original object. You can not change the reference, but once you have the reference, you can always change the content inside object that reference is pointing to.
Thanks for a quick response sir…. And thats what my point is if we get the reference then we can change the content
but see the following code…
package com.immutable.test;
public class Test1 {
private int num;
public Test1(int num) {
this.num = num;
}
public int getNum(){
return num;
}
public String toString(){
return num+””;
}
}
package com.immutable.test;
public class Test2 {
public static void main(String[] args){
Test1 test1 = new Test1(5);
System.out.println(test1);
modify(test1.getNum());
System.out.println(test1);
}
public static void modify(int num){
num = 15;
}
}
Output : 5
5
As here also I’m passing the variable num by getting it through Test1 class’s instance and changing the value in modify method..but its not reflecting…
I’m confused here why so..please explain me and so sorry for bothering you again
Thanks!
And one more thing Sir, java supports call by value and not call by reference..so in modify method whatever we are passing we are just passing the value and not the variable itself..so any change in the method for that variable is not reflecting there….Please clarify my doubts
Sir, I misunderstood one of your point, so am clarify with what you were telling as int is just a primitive data type, its neither mutable or immutable rather it depends upon our implementation…
Thanks for your patience and I personally like your blog as it clarifies many things..Thanks Once again!!!
Your welcome. In between, I would like you to go through this post, as it will help you in clearly defining the term “call by value” in context of java, only in case if you have any doubt.
https://howtodoinjava.com/java/basics/java-is-pass-by-value-lets-see-how/
below is a simple code that i wrote taking inspiration from your code obviously,
now can you explain how the code is you posted is immutable and the code i posted is mutable
///////////////////////////
import java.util.Date; public class ImmutableDemo { Date date; String string; public ImmutableDemo(Date date,String string) { this.date = date; this.string = string; } public static void modify(Date dateNew,String stringNew) { dateNew = new Date(dateNew.getTime() + 86400000); stringNew = "SOMETHING"; } @Override public String toString() { return date + " %%% " + string; } public static void main(String[] args) { ImmutableDemo id = new ImmutableDemo(new Date(), "NOT SOMETHING"); System.out.println(id); modify(id.date, id.string); System.out.println(id); } }//////////////////////
Output: (content is unchanged)
Tue Jun 17 15:51:21 IST 2014 %%% NOT SOMETHING
Tue Jun 17 15:51:21 IST 2014 %%% NOT SOMETHING
I changed your modify method to below:
public static void modify(Date dateNew,String stringNew) { dateNew.setYear(2009); //Updated the year stringNew = "SOMETHING"; }Now output is:
Tue Jun 17 16:30:30 IST 2014 %%% NOT SOMETHING
Thu Jun 17 16:30:30 IST 3909 %%% NOT SOMETHING
Hello Lokesh,
This explanation is somewhat full of confusion. In the Class you have used 3 variables, out of them two are String and Integer which you are trying to modify (to show that these cannot be changed as the class is immutable). But these two variables are itself immutable so these cannot be changed whether the class is mutable or immutable.
3 variables are: String, Integer and Date. Date is mutable.
@Lokesh: Can you clarify a point ?
What is exactly the need of having a static method with the name createNewInstance ? We can directly call the constructor when we create a object with new operator.
To be more precise what will be the difference between creating an object directly calling the constructor (making it public) and having a method to create an instance of the immutable class ?
According to me an immutable class is a class for which if an instance is created , there should be no means/method associated with the class which can change the state of the object. For eg String class has no method which returns void and changes the String. All functions of String class will always return a new String
Similar to that , I suppose having an instance creation method is not needed for making a class Immutable
Please correct me if I’m wrong anywhere
Yes, you are right. The method
createNewInstance()is not mandatory and completely optional “ONLY IF” the constructor return you a fully prepared object. This method has absolutely nothing to do with immutability of class. As you can notice that I put a comment above method “Factory method to store object creation logic in single place”. So essentially it was an attempt to have object creation logic in one place. The same thing you can achieve with having multiple overloaded constructors as well.HI Lokesh,
Your blogs are very useful which clears all my doubts. But seeing about code, had a confusion on difference between Singlton and Immutable class?
Singleton means only one instance per JVM. There is no restriction that you cannot change the state of instance.
Immutable means you cannot change the state of instance once created. Though you can have multiple instances with same state data.
Hi Lokesh,
According to your example, the output ( content will be unchanged ), if our class is immutable.
but the line tryModification(im.getImmutableField1(),im.getImmutableField2(),im.getMutableField()); is not going to change the content of instance im in all cases, even our class and attribute is final or not. we are just passing the value via parameter in tryModification method, we are not changing the values of im in any ways.
correct me if i am wrong.
Thanks,
pallav
Inside method I am trying to change state in
"mutableField.setDate(10);"You have not talked about map immutable and also reflection effect
Would you like to add something here? I will appreciate if you do so.
Hi Lokesh,
Your articles are really good and helpful. I want to understand the real advantage of making the constructor private and providing the factory method to create the instance while making a class Immutable. In your example, if you make the constructor as public and remove the factory method, how is it going to affect the immutability of this class. Can you please explain it in detail? Thanks
There is no absolute requirement for making constructor private. We have public constructor in String class and it’s good example of immutability. Factory method gives a meaningful name to the process of object creation, specially when class has multiple constructors with different number of parameters. In above example also, there will not be any behavioral change. It’s about only good practice.
I respectfully disagree.
You point out at the very beginning of your article: “An immutable class is one whose state can not be changed once created.” That means if I instantiate an object (im) of type ImmutableClass with initial values of 100, “test”, and “2013-10-14”, those values should NEVER, EVER change.
Well, guess what? If I can manipulate an “old reference” to an object (the Date d) stored INSIDE the object (im), then I’ve not only changed d, I’ve changed the object im as well! You *do not* want to allow somebody to be able to do that! That is precisely the whole point of immutable classes- to prevent this kind of chicanery!
In your original article, you included a link to Java documentation. From that link:
“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.”
Unfortunately, that is *exactly* what your example does! It stores a reference (in mutableField) to an external, mutable object (Date d) passed to the constructor!
The good news is that there is an easy solution. What you need to do is create a defensive copy in your constructor:
this.mutableField = new Date(date.getTime());
Then, I can manipulate the original Date (d) that I pass in to the constructor all I want and it won’t affect my instance of ImmutableClass at all, since the internal date in im is now a completely different Date object (that just happens to be set to the same time as d initially was).
Perfect. I see what you meant in previous comment. Agree. I will update the example with defensive copy so that others can also refer to same technique. Thanks for your contribution.
I think there might be a problem in your example, as you do not make a defensive copy of the Date in the constructor.
For example, try this for your test program:
Date d = new Date();
ImmutableClass im = ImmutableClass.createNewInstance(100,”test”, d);
System.out.println(im);
d.setMonth(1);
System.out.println(im); // date is changed.
Code you tried is flawed. You are not getting the date object from Immutable class, you are using an old reference which you passed to immutable class. Try asking the date object from immutable class and then change it.
Hi Lokesh, I have little problem to understand the conversation between you and Stefan.According to Stefan-“First: your class does not follow your own rules, because mutableField1 and mutableField2 are not final.”
And in your reply you said like “First point: fields are not final because i want to set them in constructor which it commonly seen in all JDK supplied immutable classes. Making them final will give compile time error.”
But whatever I have seen above,I have not find any non-final field.So it will be very kind of your side if you elaborate this more.Please!!!
Thankyou
Gaurav, I tried hard to remember and it is what I can recall so far. Previously field declaration was like :
private Integer immutableField1 = null; //Initialized with null
Putting final in above statement was causing error while setting value because of obvious reasons. [You cannot change value once initialized for final variables]. So what I did later, I declared the variables like:
private final Integer immutableField1;
Now I am able to initialize anywhere I want, but obliviously before object is fully constructed.
Also taken from “Effective Java,”
An immutable class copies mutable data, both on input and on output. You see this most often with java.util.Date. Imagine a DateRange class. Its constructor should look like:
public DateRange(final Date start, final Date end) {
this.start = new Date(start.getTime());
this.end = new Date(end.getTime());
if (!this.start.before(this.end)) {
throw new DateRangeException(this.start, this.end); //Write this, or use an IAE instead.
}
An immutable class either is not Serializable, or it uses readResolve to maintain class invariants.
public Object readResolve() {
return new DateRange(start, end);
}
This way, no one can falsify a serialized stream.
Thanks for pointing out serialization issue. Yes, i agree. A class should maintain its state even in case of serialization/ de-serialization. In between, in my example, i have made class serializable . So, if it had been, i would have added readResolve() like this;
//pseudo code
readResolve()
{
return this;
}