List mutability
Since List
is an interface, the only promise it makes is: "these are the methods you will get".
The List
interface describes a mutable List. Notice that it has functions such as add()
, set()
and remove()
. But notice also that these mutators are designated as "optional" operations.
There exist implementations of the List
interface which are, in practice, immutable.
List<Integer> mutable = new ArrayList<>();
mutable.add(1);
List<Integer> immutable = Collections.unmodifiableList(mutable);
// try to modify the list
immutable.add(2);
// Exception in thread "main" java.lang.UnsupportedOperationException
Collections.unmodifiableList()
returns an instance of the List
implementation Collections.UnmodifiableList
.
Collections.UnmodifiableList
forwards all calls of immutable List
functions, correctly to the underlying List
. Whereas it implements all mutable List
functions by throwing java.lang.UnsupportedOperationException
.
List element mutability
If we do:
List<Date> mutable = new ArrayList<>();
mutable.add(new Date());
List<Date> immutable = Collections.unmodifiableList(mutable);
Date myCoolDate = immutable.get(0);
Can we mutate myCoolDate
? Absolutely.
myCoolDate.setTime(99999); // works! mutates the original Date object in the `List`.
The List
— whether immutable or otherwise — stores copies of references to objects. Once we have a reference to the object (Date myCoolDate = immutable.get(0);
), we can mutate the object freely.
The items in an immutable list have no immutability guarantee. They are exactly as mutable as they have always been.