The distinct case, common to all three examples you've posted, is adding a null value to a non-empty TreeSet. This is when the NullPointerException happens.
When adding an element to a TreeSet, the implementation has to find a place for the item being inserted. When there aren't any item present yet (ie. when the TreeSet is empty), there isn't any comparison to do and the item is simply placed into the set as a root of the tree. However, when the set isn't empty, a position for the new item must be found, and this is done by comparing the new item with items already in the set. This is the problem, since TreeSet constructed without a custom comparator uses the Comparable.compareTo() method for these comparisons, and these methods by definition cannot handle null values.
It is possible to construct a TreeSet to which a null value can be placed, by using a custom comparator which correctly handles null values (that is, compares two nulls as being the same, and compares nulls to non-null values consistently).
The documentation of TreeSet is somewhat lacking in this aspect. The possibility of using a null-permitting comparator is only indirectly referred to in documentation of several methods (such as TreeSet.add()), where it states the following:
NullPointerException - if the specified element is null and this set uses natural ordering, or its comparator does not permit null elements
posted 5 years ago
I think that is an unfortunate inconsistency the API writers have. Sometimes they mention null prohibitions in the method descriptions and sometimes only once in the heading of the class. String is a bad example of the latter.
posted 5 years ago
I tried this on JDK8u40If I uncomment any of the lines 23 27 or 29 I seem to get an Exception.
Campbell Ritchie wrote:I hadn't expected an Exception on an empty Set.
Oh, I haven't understood you get the exception on that very statement.
Interesting. Looks like a check was added in some newer version of Java. I guess they do an additional check on inserting the first element, such as comparing it to itself. I'll have a look into the JDK sources later.
Since at least Java 7 (possibly earlier, can't check), TreeMap.put (which is being used by TreeSet.add) starts like this:
So if the map is empty (the root is null), the key is indeed compared to itself.