- Immutable class in java
- Need of Immutable Classes
- Popular Immutable classes in java:
- Example of String as an immutable class
- Create Custom Immutable Class:
- Simple Example of Custom Immutable Class:
- Mutable Objects in Immutable Class
- Advantages/Benefits of immutable class.
- Disadvantages of immutable classes.
- Immutable class in java
- Immutable class in java?
- benefits of immutable class?
- How to create an immutable class?
- Immutable class in java example
- Immutable class with the mutable object in java
- Why Deep Copy is important for immutability?
Immutable class in java
Immutable Object: A object is know as immutable if it’s state can not be changed over-time or we can say after object creation.
Need of Immutable Classes
In current days, most of the applications are running into multi-threading environment which results into concurrent modification problems.
Popular Immutable classes in java:
All wrapper classes (java.lang.Integer, java.lang.Byte, java.lang.Character, java.lang.Short, java.lang.Boolean, java.lang.Long, java.lang.Double, java.lang.Float), String class, java.lang.StackTraceElement, java.math.BigInteger, java.math.BigDecimalall, java.io.File, java.awt.Font, java.awt.BasicStroke, java.awt.Color, java.awt.Cursor, java.util.Locale, java.util.UUID, java.net.URL, java.net.URI, java.net.Inet4Address, java.net.Inet6Address, java.net.InetSocketAddress, most subclasses of java.security.Permission except java.security.PermissionCollection and subclasses, all classes of java.time except DateTimeException and number of collection classes are immutable classes in java.
Example of String as an immutable class
public class Main { public static void main(String[] args) { String testString1 = "website"; System.out.println("testString1: " + testString1); String testString2 = testString1 + ".com"; System.out.println("testString2: " + testString2); System.out.println("testString1: " + testString1); } }
testString1: website testString2: website.com testString1: website
testString1: website testString2: website.com testString1: website
Create Custom Immutable Class:
You can write your own immutable class, when creating immutable class just keep in mind that after creating an object of this class object can’t be modified. Any change in existing object result into new object.
- Make final class so that it cannot inherit.
- Object state is made up of its properties, declare all properties final. So that its properties value will remain constant.
- Object properties value can be set using setter methods, so only define getter methods for all properties.
- Always return a new class instance from the methods which can modify the state of the class.
- Use deep copy instead of shallow copy, while initializing the properties by constructor.
- In getter methods, always perform cloning and return the clone copy instead of actual object reference.
Simple Example of Custom Immutable Class:
ImmutableClassExample.java
/** * This program is used to create a immutable class. * @author w3spoint */ final class Student{ //declare all properties final. final String rollNo; public Student(String rollNo){ this.rollNo = rollNo; } //only create getter method. public String getRollNo() { return rollNo; } } public class ImmutableClassExample { public static void main(String args[]){ //creating Student object. Student obj = new Student("MCA/07/06"); System.out.println(obj.getRollNo()); } }
Now, Let’s move to some complex scenarios
Mutable Objects in Immutable Class
Here, we are creating Address class which is a mutable class and will use the Address objects into ImmutableEmployee class which is immutable.
Address.java:
public class Address { private String addressLine; private String city; private String state; private String pinCode; public String getAddressLine() { return addressLine; } public void setAddressLine(String addressLine) { this.addressLine = addressLine; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } public String getState() { return state; } public void setState(String state) { this.state = state; } public String getPinCode() { return pinCode; } public void setPinCode(String pinCode) { this.pinCode = pinCode; } }
ImmutableEmployee.java:
public class ImmutableEmployee { private final String name; private final long id; private final Address address; public ImmutableEmployee(String name, long id, Address address) { super(); this.name = name; this.id = id; this.address = address; } public String getName() { return name; } public long getId() { return id; } public Address getAddress() { return address; } }
MainTest.java:
public class MainTest { public static void main(String[] args) { Address address = new Address(); address.setAddressLine("Address line 1"); address.setCity("Test City"); address.setState("Test State"); address.setPinCode("123456"); ImmutableEmployee immutableEmployee = new ImmutableEmployee("Jai", 10, address); System.out.println(immutableEmployee.getName() + "'s city before modification: " + immutableEmployee.getAddress().getCity()); address.setCity("Modified City"); System.out.println(immutableEmployee.getName() + "'s city after modification: " + immutableEmployee.getAddress().getCity()); } }
Jai's city before modification: Test City Jai's city after modification: Modified City
Jai’s city before modification: Test City Jai’s city after modification: Modified City
As you can see in the output, Objects state is being changed if we modify the mutable object property of Immutable class object. So, as per #5, we will use deep copy instead of shallow copy when initializing the properties via constructor.
Constructor of ImmutableEmployee class will be:
public ImmutableEmployee(String name, long id, Address address) { super(); this.name = name; this.id = id; Address cloneAddress = new Address(); cloneAddress.setAddressLine(address.getAddressLine()); cloneAddress.setCity(address.getCity()); cloneAddress.setState(address.getState()); cloneAddress.setPinCode(address.getPinCode()); this.address = cloneAddress; }
public ImmutableEmployee(String name, long id, Address address)
Output with above change:
Jai's city before modification: Test City Jai's city after modification: Test City
Jai’s city before modification: Test City Jai’s city after modification: Test City
Result seems good but our class in not fully immutable yet. Change MainTest class code with below code and see the result.
Updated MainTest.java
public class MainTest { public static void main(String[] args) { Address address = new Address(); address.setAddressLine("Address line 1"); address.setCity("Test City"); address.setState("Test State"); address.setPinCode("123456"); ImmutableEmployee immutableEmployee = new ImmutableEmployee("Jai", 10, address); System.out.println(immutableEmployee.getName() + "'s city before modification: " + immutableEmployee.getAddress().getCity()); immutableEmployee.getAddress().setCity("Modified City"); System.out.println(immutableEmployee.getName() + "'s city after modification: " + immutableEmployee.getAddress().getCity()); } }
Output with above change:
Jai's city before modification: Test City Jai's city after modification: Modified City
Jai’s city before modification: Test City Jai’s city after modification: Modified City
You can see, city is modified again. Now, according to #6 we have to perform cloning in getter method and have to return copy of mutable object instead of actual reference. Let’s update the getAddress method code of ImmutableEmployee class.
Updated getAddress() method
public Address getAddress() { Address cloneAddress = new Address(); cloneAddress.setAddressLine(this.address.getAddressLine()); cloneAddress.setCity(this.address.getCity()); cloneAddress.setState(this.address.getState()); cloneAddress.setPinCode(this.address.getPinCode()); return cloneAddress; }
public Address getAddress()
Output with above change:
Jai's city before modification: Test City Jai's city after modification: Test City
Jai’s city before modification: Test City Jai’s city after modification: Test City
Now, our class is fully Immutable.
Advantages/Benefits of immutable class.
- Objects are thread safe by default.
- No need to synchronize immutable objects explicitly.
Disadvantages of immutable classes.
As discussed any change in immutable object result into a new object, hence result in unnecessary garbage.
Immutable class in java
Immutable objects are those objects that can’t change after creation. We can’t modify the state of an immutable object and if we try to modify it then it creates a new object. In Java, all the wrapper classes (like Integer, Boolean, Byte, and Short) and the String class are immutable. In this post, we will learn what is immutable class and how to create immutable class in java.
Immutable class in java?
A class is considered an immutable class if the object of the class is immutable. It means we can’t change the state of the object after construction. The Immutable class doesn’t provide any way for other objects to modify the state of the java immutable object.
For example, the String class is an immutable class, and we can’t modify the value of the string after initialization. You can see why String is an immutable class.
benefits of immutable class?
1. A developer can be sure that no one is able to change the state of the object. Sometimes it helps to maintain security.
2. The immutable object can’t be modified by multiple threads at the same because it creates a new object for each modification. So, we don’t need to care about synchronization.
3. The objects of the immutable class can be easily cached by VM cache or custom implementation. Because we are sure the values can’t be changed.
How to create an immutable class?
1. The class must be final so that no other classes can extend it.
2. All the data members (Variables) must be declared as final, so that, they can’t change the value of it after object creation.
3. No setter method should be there.
4. Create a getter method for each data member.
5. A parametrized constructor that will assign the value during the creation of the object.
6. If the class holds the reference of another class(mutable object):
The constructor should not assign real instances to mutable objects. It must create a clone copy of the passed argument and then use the clone copy. Make sure to always return a clone copy of the field and never return the real object instance.
Immutable class in java example
Let’s create an immutable class with the final keyword and final data members. Here we are creating an ImmutableStudent class, which is an immutable class.
final class ImmutableStudent < private final int id; private final String name; public ImmutableStudent(int id, String name) < this.name = name; this.id = id; >public int getId() < return id; >public String getName() < return name; >>
Immutable class with the mutable object in java
As we have seen custom immutable class in java in the above section. But An immutable class can contain a mutable object. Let’s see how a mutable object works in an immutable class.
final class ImmutableStudent < private final int id; private final String name; private final Address address; public ImmutableStudent(int id, String name, Address address) < this.name = name; this.id = id; this.address = address; >public int getId() < return id; >public String getName() < return name; >public Address getAddress() < return address; >> class Address < private String city; private String State; private int code; public String getCity() < return city; >public void setCity(String city) < this.city = city; >public String getState() < return State; >public void setState(String state) < State = state; >public int getCode() < return code; >public void setCode(int code) < this.code = code; >> public class ImmutableExample < public static void main(String arg[]) < Address address = new Address(); address.setCity("Chandigarh"); address.setState("Chandigarh"); address.setCode(12345); ImmutableStudent student = new ImmutableStudent(1, "Ram", address); System.out.println("Before modification: "+ student.getAddress().getCode()); student.getAddress().setCode(55555); System.out.println("After modification: "+ student.getAddress().getCode()); >>
Output: Before modification: 12345
After modification: 55555
In the above example, we are able to modify the address of the Student because the address is a mutable object. So, it is breaking the concept of immutable class. Because we are directly assigning the reference of address in the constructor, whenever the referenced address is modified outside the class, the change is reflected directly. We can fix this problem by the use of the clone instance. We will see this in the next section.
Why Deep Copy is important for immutability?
We can make an immutable class that contains a mutable object. We have to do deep cloning. You can read deep cloning from a separate post.
final class ImmutableStudent < private final int id; private final String name; Address address = new Address(); public ImmutableStudent(int id, String name, Address address) < this.name = name; this.id = id; this.address = address; >public int getId() < return id; >public String getName() < return name; >public Address getAddress() throws CloneNotSupportedException < return (Address) address.clone(); >> class Address implements Cloneable < private String city; private String State; private int code; public String getCity() < return city; >public void setCity(String city) < this.city = city; >public String getState() < return State; >public void setState(String state) < State = state; >public int getCode() < return code; >public void setCode(int code) < this.code = code; >public Object clone() throws CloneNotSupportedException < return super.clone(); >> public class ImmutableExample < public static void main(String arg[]) throws CloneNotSupportedException < Address address = new Address(); address.setCity("Chandigarh"); address.setState("Chandigarh"); address.setCode(12345); ImmutableStudent student = new ImmutableStudent(1, "Ram", address); System.out.println("Before modification: "+ student.getAddress().getCode()); student.getAddress().setCode(55555); System.out.println("After modification: "+ student.getAddress().getCode()); >>
Output: Before modification: 12345
After modification: 12345