Let me start this article by quoting Brain Goetz.
Immutable objects are simple. They can only be in one state, which is carefully controlled by the constructor. One of the most difficult elements of program design is reasoning about the possible states of complex objects. Reasoning about the state of immutable objects, on the other hand, is trivial.
Immutable objects are also safer. Passing a mutable object to untrusted code, or otherwise publishing it where untrusted code could find it, is dangerous — the untrusted code might modify its state, or, worse, retain a reference to it and modify its state later from another thread. On the other hand, immutable objects cannot be subverted in this manner by malicious or buggy code, so they are safe to share and publish freely without the need to make defensive copies.
https://quotes.pub/q/immutable-objects-are-simple-they-can-only-be-in-one-state-w-574977
An object is Immutable if we cannot change its state after we construct it.
We, as programmers, have been using Immutable Objects for a while now. The most common example of an immutable object is the String object. We cannot change the String object’s value once we assign it.
Immutability is a blessing. All the information that is contained in an object is fixed for its lifetime and cannot be changed. There are several advantages of immutable objects.
- They are easier to build and use
- They are thread safe
- Identity of multiple objects are same if encapsulated values are same
- Avoids Temporal Coupling
- We can be share them freely
- They can share their internals
Let us work our way through an example. Let us assume we have a plain simple POJO class called Name. It contains 2 attributes called firstName and lastName.
public class Name { private String firstName; private String lastName; public void setFirstName(String firstName) { this.firstName = firstName; } public String getFirstName() { return firstName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getLastName() { return lastName; } // auto generate equals, hashCode and toString methods. }
Using Name class.
Name name = new Name(); name.setFirstName("Arya"); name.setLastName("Stark");
The above code represents a POJO class. The object “name” is not immutable as we can change the state of the object once we create it. Before we refactor the class to make it immutable let us first walk through the advantages of immutability because we need to know how much helpful it is.
1. They are easier to build and use
2. They are thread safe
Immutable objects are inherently thread-safe. They do not require synchronization as multiple threads who are accessing it concurrently can not corrupt them. It would be the easiest way to achieve thread-safety using immutable objects.
3. Identity of multiple objects are the same if encapsulated values are same
Name name1 = new Name(); name1.setFirstName("Arya"); name1.setLastName("Stark"); Name name2 = new Name(); name2.setFirstName("Arya"); name2.setLastName("Stark"); name1.equals(name2); // true name2.setLastName("Baratheon") name1.equals(name2); // false
This looks ok as we are used to using the mutable objects but this can cause serious issues if we use Name class as key to HashMap.
Name name = new Name(); name.setFirstName("Arya"); name.setLastName("Stark"); Map<Name, String> map = new HashMap<Name, String>(); map.put(name, "some string"); map.containsKey(name); // true name.setLastName("Baratheon"); map.containsKey(name); // false
These issues are extremely hard to debug. Encapsulated values need to be left alone. If the need arises to change those values, it is better to create a new object with new values rather than changing it. But remember, if you provide setter methods, i.e. mutators, then people will use them without giving a thought. Better to create new object and copy values from one object to newly created object.
4. Avoids Temporal Coupling
I hate temporal coupling. It is the worst thing. Temporal coupling means that one or more members or attributes need to be invoked in a particular order. Example:
WebRequest webRequest = new WebRequest(); webRequest.setURI("http://www.justamonad.com/v1/articles"); webRequest.setRequest("some json request"); WebResponse webResponse = webRequest.post();
The above code needs URI and request set before post() method is invoked. So a client needs to know the implementation details to make a web request. While designing class and methods, we should assume that client should be able to use them with minimal supervision. A better alternative to above can be:
WebResponse webResponse = new WebRequest("uri", "json request").post();
5. We can share freely them
As the internal state of immutable objects cannot be changed, we can share it freely around the system. One example of this is Integer.valueOf(int i) method. This method converts int to Integer object. But underneath there is a private static class in Integer class called IntegerCache, which creates a cache of 256 Integer objects representing from int i = -127 to int i = 128. These objects can be used by us and shared freely as Integer objects are immutable.
6. They can share their internals
Let us understand this with an example. Internally String object is stored as char[] array. Consider the below example:
String str = "Good Morning"; String newStr = str.substring(5);
newStr is a new String returned by the substring() method. Internally substring method uses char[] that was created when the original String was created and it will copy the content based on index to new char[].
Another example is BigInteger, where internal representation is based on magnitude and sign. If we called the method negate() on BigInteger object, then it will create a new BigInteger object with an inverted sign and same magnitude.
Classes should be immutable unless there is excellent reason to make it mutable. If immutability renders impractical for certain use cases, then limit the mutability as much as possible.
Conclusion
That is all on advantages of Immutable Objects. If I missed any of advantages, please let me know in comments section. I would be more than happy to add them.