Why aren't Java Collections remove methods generic?

remove() (in Map as well as in Collection) is not generic because you should be able to pass in any type of object to remove(). The object removed does not have to be the same type as the object that you pass in to remove(); it only requires that they be equal. From the specification of remove(), remove(o) removes the object e such that (o==null ? e==null : o.equals(e)) is true. Note that there is nothing requiring o and e to be the same type. This follows from the fact that the equals() method takes in an Object as parameter, not just the same type as the object.

Although, it may be commonly true that many classes have equals() defined so that its objects can only be equal to objects of its own class, that is certainly not always the case. For example, the specification for List.equals() says that two List objects are equal if they are both Lists and have the same contents, even if they are different implementations of List. So coming back to the example in this question, it is possible to have a Map<ArrayList, Something> and for me to call remove() with a LinkedList as argument, and it should remove the key which is a list with the same contents. This would not be possible if remove() were generic and restricted its argument type.


Josh Bloch and Bill Pugh refer to this issue in Java Puzzlers IV: The Phantom Reference Menace, Attack of the Clone, and Revenge of The Shift.

Josh Bloch says (6:41) that they attempted to generify the get method of Map, remove method and some other, but "it simply didn't work".

There are too many reasonable programs that could not be generified if you only allow the generic type of the collection as parameter type. The example given by him is an intersection of a List of Numbers and a List of Longs.


Because if your type parameter is a wildcard, you can't use a generic remove method.

I seem to recall running into this question with Map's get(Object) method. The get method in this case isn't generic, though it should reasonably expect to be passed an object of the same type as the first type parameter. I realized that if you're passing around Maps with a wildcard as the first type parameter, then there's no way to get an element out of the Map with that method, if that argument was generic. Wildcard arguments can't really be satisfied, because the compiler can't guarantee that the type is correct. I speculate that the reason add is generic is that you're expected to guarantee that the type is correct before adding it to the collection. However, when removing an object, if the type is incorrect then it won't match anything anyway. If the argument were a wildcard the method would simply be unusable, even though you may have an object which you can GUARANTEE belongs to that collection, because you just got a reference to it in the previous line....

I probably didn't explain it very well, but it seems logical enough to me.