I am sure a lot of java developers have heard of String being immutable in Java. But what are the advantages of making a certain object immutable or when should we make an object immutable and most importantly how do we make objects immutable? These are some of the questions that I always answer when mentoring new java developers.
I always wanted to document the answers so that a major portion of developers can benefit from this pattern. Lets answer these questions one by one. So the first up we should define what exactly is immutability. Heres a perfect definition: An immutable object is one that, after creation, is `read-only'; it cannot be changed; none of its methods changes it. This defines immutability perfectly. The String class in java and all the primitive wrappers like Integer, Long etc. are immutable.
But what advantages will it give if we can’t change the object after it’s creation. Ever seen developers using the + operator for string concatenation and the look on their faces when they get to know that they have managed to load test the Garbage Collector with their simple piece of code . Anyways back to the question. The main advantage of immutability is that you can easily cache the object w/o worrying about cache poisoning or objects getting changed in the cache when someone changes the object returned from it. Remember the String class is cached so are all the wrapper classes to a certain limit.
This also answers our second question i.e., whenever you want to cache objects make them immutable.
Lets move on to the last question. How to make objects immutable? The simplest answer that people always come up with is not creating any mutators (setters) for the object so that you create the object using a constructor or a factory and you can never modify the object. But thats not totally true. In case your object only contains primitives which are passed by value this technique will work but in case the object contains other objects which are passed by reference then you have a serious flaw in your implementation. There are two cases that need to be handled.
- What to do when the object is passed in while constructing our immutable object?
- What to do when returning these objects using the accessors (getters)?
The only solution that comes to mind is to make a defensive copy of these objects whenever they are passed or passed out. Okay what else? can anyone think of any other pitfalls. Well there is one more. You should always make your immutable class final. The reason being we don’t want it to be sub-classed, Why? because if you do you can very easily modify the state of the object if they are declared protected. But what if they are declared as private? Even in that case it is pretty easy to break the contract and give the impression that the object is immutable when its not. Reason why the String class is also declared as final
What to do if we want to modify the object? According to the discussion above it seems like we are not providing any mutators and the only solution that remains is to explicitly construct a new object with the modified values. Well there are two solutions
- Provide mutators(setters) for the object. But instead of following the normal mutator pattern of returning nothing we return the new object with the changed values.
- Provide a separate class which allows us to modify our object. Take the example of String and the StringBuffer/StringBuilder class. When we want to modify a String w/o creating temporary objects we use StringBuffer/StringBuilder class and when we are done we call its toString method to get the String object with our desired value.
The latter approach is quite helpful as it allows a simple method to make modifications on the immutable object w/o breaking the contract of immutability and doesn’t even creates the temporary objects.
Lets summarize the whole pattern in few points:
- Make sure the immutable class is declared as final.
- If only primitives are used in the immutable class then we can skip all the mutators and just provide the accessors.
- In case the immutable class contains other objects, make defensive copies of these objects whenever they are passed in through the constructor and passed out using the accessors.
- In case there is a need for modifying the object state w/o creating many temporary objects provide a separate mutator class to do the job.
- Also declare all the fields final. It is good for two reasons, it saves you from accidentally changing the value and there is a compile time error if you forget to initialize it. final is your fiend, use it. Thanks Ben for the suggestion.
Always make objects immutable when you want to cache them. This will save you from lots of hard to find bugs. Trust me I have been through it and I know how difficult it is to debug these issues in production environment when customers/management is screaming at you to get them resolved in hours.
As a final note there is one more way to make the object immutable. Plain old documentation to the rescue. Just document clearly that the object shouldn’t be modified after its creation for the correct working But I guess thats an ideal solution where every developer follows what the documentation says or just even reads it