Most of the objects in Java are mutable. It means that their state/fields can be changed after the object was created. The examples of those are: ArrayList, Calendar, StringBuilder.
An object is immutable if its state/fields cannot be changed after the object is constructed. In practice it means that:
- The object class must not have any mutable methods like setters.
- Every object contained within this object is also immutable (or otherwise protected from modification).
- If the object contains collection, it must be impossible to add new elements, remove existing elements or modify the value of any element. Every element of the collection must be immutable (or otherwise protected from modification).
- Every field of the object is final and private.
- The object class is declared as final.
The most notable examples of immutable classes are String, Integer and other wrappers of basic types, LocalDateTime and other classes from Java 8 Date and Time API.
Benefits of immutable objects
Reliance on immutable objects is widely accepted strategy for creating simple and reliable code. Few of the most notable benefits of immutable objects are listed below:
- These are simpler to construct, test, use and easier to reason about because they can never be changed. Class invariant is checked once and never changed. There is no need for defensive copying.
- Immutable objects are excellent candidates for Map and Set keys because these cannot change value while in the collection. Immutable objects prevents key modification.
- The internal state of the object stays consistent even after exception is thrown. This is not the case for many mutable objects.
- Immutable objects can be easily and safely cached because these are not going to change.
- Immutable objects are automatically thread-safe so the whole problem of thread synchronization is gone. Additionally, these are particularly useful in concurrent application.
Cost of immutable objects
Immutability may have a performance cost because completely new object needs to be created as opposed to updating an existing object in place. But often this cost is overestimated and can be reduced by the elimination of thread synchronization, easier/faster garbage collection and specialized builders.