Do Collections.unmodifiableXXX methods violate LSP? [closed]

LSP says that every subclass must obey the same contracts as the superclass. Wether or not this is the case for Collections.unmodifiableXXX() thus depends on how this contract reads.

The objects returned by Collections.unmodifiableXXX() throw an exception if one tries to call any modifying method upon them. For instance, if add() is called, an UnsupportedOperationException will be thrown.

What is the general contract of add()? According to the API documentation it is:

Ensures that this collection contains the specified element (optional
operation). Returns true if this collection changed as a result of the
call. (Returns false if this collection does not permit duplicates and
already contains the specified element.)

If this was the full contract, then indeed the unmodifiable variant could not be used in all places where a collection can be used. However, the specification continues and also says that:

If a collection refuses to add a particular element for any reason
other than that it already contains the element, it must throw an
exception (rather than returning false). This preserves the invariant
that a collection always contains the specified element after this
call returns.

This explicitly allows an implementation to have code which does not add the argument of add to the collection but results in an exception. Of course this includes the obligation for the client of the collection that they take that (legal) possibility into account.

Thus behavioural subtyping (or the LSP) is still fulfilled.
But this shows that if one plans to have different behaviours in subclasses that must also be foreseen in the specification of the toplevel class.

Good question, by the way.

Leave a Comment