Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java collections API: why are Unmodifiable[List|Set|Map] not publicly visible classes?

Tags:

Collections.unmodifiableList(...) returns a new instance of a static inner class UnmodifiableList. Other unmodifiable collections classes are constructed same way.

Were these classes public, one had two advantages:

  • ability to indicate a more specific return value (such as UnmodifiableList), so an API user wouldn't come to the idea of modifying that collection;
  • ability to check during runtime if a List is instanceof UnmodifiableList.

So, were there any advantages not to make those classes public?

EDIT: No definitely convincing arguments were presented, so I choose the most upvoted answer.

like image 463
java.is.for.desktop Avatar asked Nov 28 '10 11:11

java.is.for.desktop


People also ask

What is Unmodifiable list in Java?

The unmodifiableList() method of java. util. Collections class is used to return an unmodifiable view of the specified list. This method allows modules to provide users with “read-only” access to internal lists.

How do you know if a list is Unmodifiable?

I suggest using "addAll(Collections. emptyList());" instead of add(null) to test for immutable. This will raise the UnsupportedOperationException if immutable and does not modify the list if mutable.

How do you make an unmodifiable list modifiable?

The solution to this problem is quite simple and is highlighted in the following code. final List<String> modifiable = new ArrayList<>(); modifiable. add("Java"); modifiable. add("is"); // Here we are creating a new array list final List<String> unmodifiable = Collections.


2 Answers

Personally I completely agree with you. At the core of the problem is that fact that Java's generics are not covariant, which, in turn, is because Java's collections are mutable.

It is not possible for Java's type system to codify a type that seems to have mutators is actually immutable. Imagine if we were to start designing some solution:

interface Immutable //marker for immutability  interface ImmutableMap<K, V> extends Map<K, V>, Immutable 

But then ImmutableMap is a subclass of Map, and hence Map is assignable from ImmutableMap so any method which returns such an immutable Map:

public ImmutableMap<K, V> foo(); 

can be assigned to a Map and can therefore be mutated at compile time:

Map<K, V> m = foo(); m.put(k, v); //oh dear 

So, you can see that the addition of this type has not actually prevented us from doing anything bad. I think for this reason a judgement was made that it did not have enough to offer.


A language like scala has declaration-site variance annotations. That is, you could specify a type as being covariant (and hence immutable) as Scala's Map is (actually it's covariant in its V parameter). Hence your API can declare whether its return type is mutable or immutable.

As another aside, Scala lets you declare intersection types so that you don't even need to create the ImmutableXYZ interface as a separate entity, you could specify a method to return:

def foo : XYZ with Immutable 

But then scala has a proper type system, whereas Java does not

like image 65
oxbow_lakes Avatar answered Nov 05 '22 07:11

oxbow_lakes


I think both advantages are there but are not that useful. The main problems remain the same: UnmodifiableList still is a List and thus all the setters are available and the underlying collections still are modifiable. Making the class UnmodifiableList public would add to the illusion of being unmodifiable.

The nicer way would be for the compiler to help, but for that the collection class hierarchies would have to changed a lot. E.g., the collection API of Scala is way more advanced in that respect.

A disadvantage would be the introduction of at least three additional classes / interfaces into the API. Because of them not being that useful, I think leaving them out of the API is a good choice.

like image 31
Christoph Dietze Avatar answered Nov 05 '22 07:11

Christoph Dietze