Working with an immutable class is always easier. Its state does not change, which means it can be accessed in a multi-threaded environment without additional synchronization. Functions that depend only on the instance's state will return the same result from one call to another—this simplifies, for example, the implementation of hashCode(). Also, instead of using multiple identical instances, a single cached object can be used, saving (the Flyweight pattern).
Steps to make a class immutable:
1. Prevent class extension – either declare the class as
final
, or restrict access to all mutative methods to any subclasses, as detailed in the following points;2. Make all fields final;
3. Do not expose mutator methods, that change the state;
4. Do not expose mutable reference type fields (objects, arrays) – if an object under the reference is not immutable, a deep copy should be returned instead (defensive copying);
5. Create objects properly (details in the next post).
If you need the benefits of an immutable object but also need to modify it occasionally, the copy on write approach may be suitable: each mutator method should mutate and return a newly created copy of the object, not the original. The original remains unchanged.