When I dig into the gs-collection source for ImmutableList
, it does not extends java.util.List
. However the class javadoc mentioned that All ImmutableList implementations must implement the java.util.List
.
Why must ask the implementation to implement java.util.List
and not the ImmutableList
itself to extend java.util.List
?
Why doesn't ImmutableList
extend List
?
ImmutableCollection
doesn't extend java.util.Collection
(and ImmutableList
doesn't extend java.util.List
) because Collection
has mutating methods like add()
and remove()
. If immutable collections had these methods, they would always have to throw UnsupportedOperationException
. For users of immutable collections, it would be strange to see add()
and remove()
in auto-complete choices as callable methods.
Why does the Javadoc impose a contract that all ImmutableList
implementations also implement List
?
It comes down to equality. An ImmutableList
ought to equal a List
, assuming both lists have the same contents in the same order. List.equals()
imposes a Javadoc contract which states:
Returns true if and only if the specified object is also a list, both lists have the same size, and all corresponding pairs of elements in the two lists are equal.
What does it mean that "the specified object is also a list?" We can see in AbstractList.equals()
that it means instanceof List
.
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof List))
return false;
...
}
So all ImmutableList
implementations must also implement List
for equals()
to work in a symmetric way. The immutable collection factories already hide implementation details like the fact that an immutable list with a single element is implemented by an ImmutableSingletonList
. It also winds up hiding the List
interface.
Interop
A benefit of this design is that ImmutableList
can be cast to List
which is important for interop with existing APIs.
// Library method - cannot refactor the parameter type
public void printAll(List<?> list)
{
for (Object each : list)
{
System.out.println(each);
}
}
ImmutableList<Integer> immutableList = Lists.immutable.with(1, 2, 3);
List<Integer> castList = immutableList.castToList();
printAll(castList);
// also works
printAll((List<?>) immutableList);
// throws UnsupportedOperationException
castList.add(4);
Note: I am a developer on GS Collections.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With