8

From the Java 6 TreeSet<E> Documentation:

boolean remove(Object o):
    Removes the specified element from this set if it is present.

Why does this accept an Object instead of the generic type E? The only objects that can be added are of type E, so it follows that the only removable type should be of type E.

ComputerDruid
  • 16,897
  • 1
  • 19
  • 28
  • 5
    related: http://stackoverflow.com/questions/857420/what-are-the-reasons-why-map-getobject-key-is-not-fully-generic – Paul Bellora Nov 04 '11 at 21:11
  • possible duplicate of [Why aren't Java Collections remove methods generic?](http://stackoverflow.com/questions/104799/why-arent-java-collections-remove-methods-generic) – PhoneixS Aug 07 '13 at 15:50

4 Answers4

9

Taking the answer from the first comment posted:

Myth:

A popular myth is that it is stupid and evil, but it was necessary because of backward compatibility. But the compatibility argument is irrelevant; the API is correct whether you consider compatibility or not.

Real reason:

Uniformly, methods of the Java Collections Framework (and the Google Collections Library too) never restrict the types of their parameters except when it's necessary to prevent the collection from getting broken.

Read more here: Why does Set.contains() take an Object, not an E?

zengr
  • 38,346
  • 37
  • 130
  • 192
4

remove(), like get() is required to work when given an equal element (in terms of .equals()). In Java, it is possible (and in some cases, required) for objects of different classes to be equal. Hence, you shouldn't restrict the type.

newacct
  • 119,665
  • 29
  • 163
  • 224
0

Well, each E is also an Object, and perhaps you have the E not as E at the moment (e.g from an Event source), which makes it convenient for you. Otherwise you just have to cast it to E only to remove it.

From an equality point of view this doesn't matter: The given object's reference address is tested if it equals a set's content, so it doesn't matter of which class it is.

Alex Schenkel
  • 728
  • 1
  • 7
  • 13
0

This is indeed a problem. If someone calls remove(o) and o's type is not E, it is usually a programming bug that tries to remove the wrong thing. Type checking failed to protect us from the bug.

Although a good IDE (IntelliJ) can detect such issues and warn us, API designers should have provided more precise signature to utilize compiler type checking. (IDE cheats here - it knows the meaning of Set.remove() because it's a standard API. IDE will not provide the same help for custom APIs)

For query API like contains(), it is OK to accept a non-E argument and return a trivial false. So we can have both

boolean contains(Object o);
boolean contains2(E o);

For mutation API like remove(), it's debatable whether it should accept a non-E argument. However the debate is going to be moot, given the reality of erasure - there is really no choice but accept non-E argument and be silent about it. Still we can have two methods

boolean remove(Object o);
boolean remove2(E o);

In most cases, programmers can call contains2/remove2 for extra type safety.

irreputable
  • 44,725
  • 9
  • 65
  • 93