Table of Contents
- Overview
- Usage of Immutable class
- Steps to create an Immutable class
- Exploring Existing Immutable classes in Java
- Examples with/without Mutable/Immutable class
- Conclusion
Let’s explore each of them.
Cover Image credits: Immutable class cover image | Image by Author Rakshit Shah
1. Overview
Immutable class means that once an object is created, we cannot change its content. In Java, all the wrapper classes (like Integer, Short, Boolean, Byte, etc.) and String class is immutable. We can create our own immutable class as well.
An object is immutable if its state cannot change after construction. Immutable objects don’t expose any way for other objects to modify their state; the object’s fields are initialized only once inside the constructor and never change again.
Always remember that,
- Primitive data types — includes byte, short, int, long, float, double, boolean, and char.
- Non-primitive data types — such as String, Arrays, Interfaces, and Classes.
In this article, we will explain point-to-point the typical steps to create an Immutable class with examples and their usages.
2. Usage of Immutable class
As per the current trend, In all IT industries, every software application must have to be distributed and multi-threaded. I know most of the developers are afraid of implementing Threads in their applications.
When it comes to multi-threaded applications, it always causes headaches for software engineers since they are required to protect the state of their objects from concurrent modifications of several threads at the same time. Hence, the developers normally use the Synchronized blocks whenever they modify the state of an object.
What you can do with immutable classes?
- States are never modified
- Every modification of a state results in a new instance, hence each thread would use a different instance and developers wouldn’t worry about concurrent modifications.
3. Steps to create an Immutable Class
- The class must be declared as final (Final class cannot be inherited)
- Data members in the class must be declared as private (It will avoid direct access)
- Data members in the class must be declared as final (Nobody can change the value of it on object instantiation or creation.)
- A parameterized constructor should initialize all the fields performing a deep copy (So that data members can’t be modified with object reference)
- Deep Copy of objects should be performed in the getter methods (To return a copy rather than returning the actual object reference)
- No setters, Don’t add any setter methods (To not have the option to change the value of the instance variable)
- When exposing methods that modify the state of the class, you must always return a new instance of the class.
- If the class holds a mutable object(s):
- Inside the constructor, make sure to use a clone copy of the passed argument and never set your mutable field to the real instance passed through the constructor, this is to prevent the clients who pass the object from modifying it afterward.
- Make sure to always return a clone copy of the field and never return the real object instance as mentioned in Step 7.
4. Exploring Existing Immutable classes in Java
You always heard about the well-known immutable class String. Once initialized its value cannot be modified. Operations like trim()
, substring()
, replace()
always return a new instance and don’t affect the current instance, that’s why we usually call trim()
like the following:
String str = "Rax";
str = str.trim();
Wrapper classes made for primitive datatypes compatibility are also examples of Immutable classes.
Integer, Float, Boolean, etc. — these classes don’t modify their state, however they create a new instance each time you try to modify them.
Float x = 1.5;
x += 5.5;
After calling x+= 5.5, a new instance is created holding the value: 7, and the first instance is lost.
If you know about other Immutable classes, feel free to write below in the comment section.
5. Examples with/without Mutable/Immutable class
Let’s go with simple and easy examples first.
1. Simple Immutable Class
public final class ImmutableEmployee {
private final int id;
private final String name;
//Parameterized Constructor
public ImmutableEmployee(int id, String name) {
this.name = name;
this.id = id;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
}
The above class doesn’t hold any mutable object and never exposes its fields in any way as they are final and private. These types of classes are normally used for caching purposes.
2. Passing Mutable Objects to Immutable Class
We create a mutable class called Age and add it as a field to ImmutableEmployee:
Age.java
public class Age {private int day; private int month; private int year;public int getDay() { return day; }public void setDay(int day) { this.day = day; }public int getMonth() { return month; }public void setMonth(int month) { this.month = month; }public int getYear() { return year; }public void setYear(int year) { this.year = year; }}
ImmutableEmployee.java
public final class ImmutableEmployee {private final int id; private final String name; private final Age age;public ImmutableEmployee(int id, String name, Age age) { this.name = name; this.id = id; this.age = age; }public int getId() { return id; }public String getName() { return name; }public Age getAge() { return age; } }
If you call the main method and check whether your class ImmutableEmployee
is immutable or not?
public static void main(String[] args) {Age age = new Age(); age.setDay(1); age.setMonth(1); age.setYear(1994); ImmutableEmployee emp = new ImmutableEmployee(1, "Rax", age);System.out.println("Rax age year before modification = " + emp.getAge().getYear());age.setYear(1995);System.out.println("Rax age year after modification = " + emp.getAge().getYear()); }
Output:
Rax age year before modification = 1994
Rax age year after modification = 1995
Understand what just happened?
We claim that ImmutableEmployee
is an immutable class
The state is never modified after construction; however, in the above example, we can modify the age of Rax even after constructing Rax object. If we go back to the implementation of the ImmutableEmployee constructor, we find that age field is being assigned to the instance of the Age argument, so whenever the referenced Age is modified outside the class, the change is reflected directly on the state of Rax. Check out Pass by value OR pass by reference article to more deeply understand this concept.
How you can fix such a situation?
As said above, in step 8 to create Immutable objects, clone instance will handle everything for you.
public ImmutableEmployee(int id, String name, Age age) {
this.name = name;
this.id = id;
Age cloneAge = new Age();
cloneAge.setDay(age.getDay());
cloneAge.setMonth(age.getMonth());
cloneAge.setYear(age.getYear());
this.age = cloneAge;
}
Output:
Rax age year before modification = 1994
Rax age year after modification = 1994
But, It is not the perfect Immutable class yet! Check the below example about how you can make it a perfect Immutable class.
3. Returning Mutable Objects From Immutable Class
As per step 7, when returning mutable fields from the immutable object(s), you should return a clone instance of them and not the real instance of the field.
To modify getAge() to return a clone of the object’s age:
public Age getAge() { Age cloneAge = new Age(); cloneAge.setDay(this.age.getDay()); cloneAge.setMonth(this.age.getMonth()); cloneAge.setYear(this.age.getYear());return cloneAge; }
It will return you perfect output for your Immutable class.
Rax age year before modification = 1994
Rax age year after modification = 1994
6. Conclusion
Advantages:
- It gives benefit for multi-threaded environment
Disadvantages:
- Memory Consumption is more because on each modification of them a new object is created in the memory.
Finally, an object is immutable if it can present only one state to the other objects, no matter how and when they call its methods. If so it’s thread-safe by any definition of thread-safe.
Reference:
[1] Java™: The Complete Reference Herbert Schildt
[2] Java First Head Book,
[3] DZone
I obtain an immense amount of satisfaction from helping others attain their goals and reach their potential through technology. Even if you wish to reach out and say "Hello", I sincerely appreciate all of the wonderful correspondence I receive each day from readers. You all enrich my life, and I hope I am able to do the same for you all as well.
If you find joy and value in what I do, please consider supporting my work with a donation — however much you can afford, it means and helps more than you can imagine.
You can give tips too using Buy me a coffee.
Discover more from 9Mood
Subscribe to get the latest posts sent to your email.
0 Comments