• Post Reply Bookmark Topic Watch Topic
  • New Topic

TreeSet adding null twice  RSS feed

 
Jo Gupta
Greenhorn
Posts: 12
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I have a question related to q50 of the Examlab practice exam 4:

Why does adding null a second time to a TreeSet create a NullpointerException?

public static void main(String[] args) {
Set ts = new TreeSet();
ts.add(null);
ts.add(null); // creates NullPointerException
}

Shouldn't the second null simply replace the first?
Or is the reason that null cannot be compared to anything?


public static void main(String[] args) {
Set ts = new TreeSet();
ts.add(1);
ts.add(null); // creates NullPointerException
ts.add(null);
}


public static void main(String[] args) {
Set ts = new TreeSet();
ts.add("String");
ts.add(null); // creates NullPointerException
ts.add(null);
}

The last two cases fail sooner, on the first ts.add(null), presumably because Integer and null are not Comparable, nor are String and null.

Is it correct therefore that the first case fails because null also cannot be compared to null?

Many thanks in advance!
JG
 
Martin Vajsar
Sheriff
Posts: 3752
62
Chrome Netbeans IDE Oracle
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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).
 
Campbell Ritchie
Marshal
Posts: 56536
172
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
That is an interesting phenomenon! I can't find anything about it in the TreeSet documentation. Under the natural ordering link, however, we can find this:-
e.compareTo(null) should throw a NullPointerException
 
Martin Vajsar
Sheriff
Posts: 3752
62
Chrome Netbeans IDE Oracle
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
 
Campbell Ritchie
Marshal
Posts: 56536
172
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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.
 
Campbell Ritchie
Marshal
Posts: 56536
172
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I tried this on JDK8u40If I uncomment any of the lines 23 27 or 29 I seem to get an Exception.
 
Martin Vajsar
Sheriff
Posts: 3752
62
Chrome Netbeans IDE Oracle
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Campbell Ritchie wrote:If I uncomment any of the lines 23 27 or 29 I seem to get an Exception.

Is that unexpected? You haven't provided a custom comparator to the TreeSet constructor which would gracefully handle nulls.

In Java 8, you can try this:

(Disclaimer: haven't tried it myself. One has to love the Java 8's default methods, though. )
 
Campbell Ritchie
Marshal
Posts: 56536
172
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I hadn't expected an Exception on an empty Set. I shall try your code and see what happens.
 
Campbell Ritchie
Marshal
Posts: 56536
172
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Prints “null” as the first element

Thank you
 
Martin Vajsar
Sheriff
Posts: 3752
62
Chrome Netbeans IDE Oracle
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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.
 
Rob Spoor
Sheriff
Posts: 21135
87
Chrome Eclipse IDE Java Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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.
 
Campbell Ritchie
Marshal
Posts: 56536
172
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
…and that is why we were getting the exceptions.

Thank you again
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!