Immutable class?
What is an immutable object?
An immutable object is one that will not change state after it is instantiated.
How to make an object immutable?
In general, an immutable object can be made by defining a class which does not have any of its members exposed, and does not have any setters.
The following class will create an immutable object:
class ImmutableInt {
private final int value;
public ImmutableInt(int i) {
value = i;
}
public int getValue() {
return value;
}
}
As can be seen in the above example, the value of the ImmutableInt
can only be set when the object is instantiated, and by having only a getter (getValue
) the object's state cannot be changed after instantiation.
However, there must be care taken that all objects that are referenced by the object must be immutable as well, or it could be possible to change the state of the object.
For example, allowing an reference to an array or ArrayList
to be obtained through an getter will allow the internal state to change by changing the array or collection:
class NotQuiteImmutableList<T> {
private final List<T> list;
public NotQuiteImmutableList(List<T> list) {
// creates a new ArrayList and keeps a reference to it.
this.list = new ArrayList(list);
}
public List<T> getList() {
return list;
}
}
The problem with the above code is, that the ArrayList
can be obtained through getList
and be manipulated, leading to the state of the object itself to be altered, therefore, not immutable.
// notQuiteImmutableList contains "a", "b", "c"
List<String> notQuiteImmutableList= new NotQuiteImmutableList(Arrays.asList("a", "b", "c"));
// now the list contains "a", "b", "c", "d" -- this list is mutable.
notQuiteImmutableList.getList().add("d");
One way to get around this problem is to return a copy of an array or collection when called from a getter:
public List<T> getList() {
// return a copy of the list so the internal state cannot be altered
return new ArrayList(list);
}
What is the advantage of immutability?
The advantage of immutability comes with concurrency. It is difficult to maintain correctness in mutable objects, as multiple threads could be trying to change the state of the same object, leading to some threads seeing a different state of the same object, depending on the timing of the reads and writes to the said object.
By having an immutable object, one can ensure that all threads that are looking at the object will be seeing the same state, as the state of an immutable object will not change.
You make a class immutable like this:
public final class Immutable
{
private final String name;
public Immutable(String name)
{
this.name = name;
}
public String getName() { return this.name; }
// No setter;
}
Following are the requirements to make a Java class immutable:
- Class must be declared as
final
(So that child classes can’t be created) - Members in the class must be declared as
final
(So that we can’t change the value of it after object creation) - Write Getter methods for all the variables in it to get Members values
- No Setters methods
Immutable classes are useful because
- They're thread-safe.
- They also express something deep about your design: "Can't change this.", When it applies, it's exactly what you need.
Immutability can be achieved mainly in two ways:
- using
final
instance attributes to avoid reassignment - using a class interface that simply doesn't allow any operation that is able to modify what is inside your class (just getters and no setters
Advantages of immutability are the assumptions that you can make on these object:
- you gain the no-side effect rule (that is really popular on functional programming languages) and allows you to use objects in a concurrent environment easier, since you know that they can't be changed in a atomic or non atomic way when they are used by many threads
- implementations of languages can treat these objects in a different way, placing them in zones of memory that are used for static data, enabling faster and safer use of these objects (this is what happens inside the JVM for strings)
In addition to the answers already given, I'd recommend reading about immutability in Effective Java, 2nd Ed., as there are some details that are easy to miss (e.g. defensive copies). Plus, Effective Java 2nd Ed. is a must-read for every Java developer.