3

From the docs of Collection.removeAll():

Throws: NullPointerException - if this collection contains one or more null elements and the specified collection does not support null elements (optional), or if the specified collection is null.

But the code below does still throw a NullPointerException:

public class TestSet { 
    public static void main(String[] args) { 
        Set set1 = new TreeSet(); 
        set1.add("A"); 
        set1.add("B"); 
        Set set2 = new HashSet(); 
        set2.add(null); 
        set1.removeAll(set2); 
    } 
} 

Can someone help me understand this behavior?

Suresh Atta
  • 120,458
  • 37
  • 198
  • 307
T-Bag
  • 10,916
  • 3
  • 54
  • 118
  • 1
    No it is not duplicate, You are just pointing to question that gives defination of NPE here i am asking something different – T-Bag Jun 15 '17 at 10:13
  • @domdom--Please remove duplicate tag, and read the question carefully. – T-Bag Jun 15 '17 at 10:16
  • 1
    "This collection" refers to the receiver of the `removeAll` call, i.e. `set1`. There are no null elements in that set. – Andy Turner Jun 15 '17 at 10:16
  • Andy, true. Sorry then, I'm going to hide under my desk now. – domsson Jun 15 '17 at 10:17
  • 1
    @AndyTurner---Mods please remove duplicate tag..this 1K + guy marked it duplicate without understanding the question – T-Bag Jun 15 '17 at 10:17
  • 2
    @EJP that's a bad duplicate. OP is not asking what a NPE is, (s)he is asking why the NPE described in the Javadoc doesn't occur in this case. It's pretty obvious why it doesn't, but that is in no way covered by that dupe. – Andy Turner Jun 15 '17 at 10:18
  • Easy to see why is throwing looking at the source of how removeAll gets implemented. At some point `if (key == null) throw new NullPointerException();` is executed in the `getEntry` method within the `TreeSet` implementation. – Davide Spataro Jun 15 '17 at 10:21
  • @EJP please check again. – T-Bag Jun 15 '17 at 10:23
  • Sorry for having wrongly voted for your question as being a duplicate; I indeed misunderstood. Now that I got it, I find this a very good question as you apparently stumbled upon an inaccuracy in the Java docs! Have my upvote. However, I can't set or remove the duplicate mark as I'm lower than 2k rep. – domsson Jun 15 '17 at 10:32
  • domdom--Thanks do you know how to unduplicate it. – T-Bag Jun 15 '17 at 10:33
  • @ScaryWombat- Its not or its AND – T-Bag Jul 19 '17 at 05:47
  • @ScaryWombat-- Seems it's issue with Java Doc8 – T-Bag Jul 19 '17 at 05:50
  • 2
    "Attempting to add an ineligible element throws an unchecked exception, typically NullPointerException or ClassCastException. Attempting to query the presence of an ineligible element may throw an exception, or it may simply return false; some implementations will exhibit the former behavior and some will exhibit the latter. More generally, attempting an operation on an ineligible element whose completion would not result in the insertion of an ineligible element into the set may throw an exception" From the guide - during removeAll - it would query Set s1 which is having null. – worker_bee Jul 19 '17 at 05:51
  • I checked java-8 docs https://docs.oracle.com/javase/8/docs/api/java/util/AbstractSet.html#removeAll-java.util.Collection- – T-Bag Jul 19 '17 at 05:52
  • But it may *not* throw NullPointerException if the *specified* collection contains one or more null elements and *this* collection does not support null elements. – T-Bag Jul 19 '17 at 05:56
  • @ScaryWombat-- Thanks ... :) could you please help me understand this i am looking into JDK code to decipher this – T-Bag Jul 19 '17 at 06:03
  • 5
    You asked this last month... – Sotirios Delimanolis Jul 19 '17 at 06:13
  • and had a great answer from @Eran - what gives? – Scary Wombat Jul 19 '17 at 06:19

2 Answers2

4

I guess that Javadoc's conditions for when NullPointerException may be thrown by removeAll are inaccurate.

TreeSet's removeAll relies on AbstractSet's implementation. That implementation iterates over all the elements of the smaller of the two sets.

In your snippet, that's the HashSet, which contains the null element. So removeAll iterates over the HashSet and attempts to remove each element it finds from the TreeSet.

However, remove of TreeSet throws a NullPointerException when trying to remove a null element from as set that uses natural ordering, or its comparator does not permit null elements.

To summarize, the NullPointerException is caused by TreeSet's remove(), which is explained in the Javadoc of remove():

Throws:

ClassCastException - if the specified object cannot be compared with the elements currently in this set

NullPointerException - if the specified element is null and this set uses natural ordering, or its comparator does not permit null elements

It's interesting to note that adding one more element to the HashSet would eliminate the NullPointerException, since in this case both Sets would have the same size, and the implementation of removeAll() would iterate over the elements of the TreeSet.

Eran
  • 387,369
  • 54
  • 702
  • 768
  • According to the stack trace, the NPE originates from `getEntry()`, no? But that's nitpicking I guess. – domsson Jun 15 '17 at 10:33
  • @domdom I could have pointed out the exact source of the NPE, but since `TreeSet`'s `remove()` already states in the Javadoc that it would throw a NPE when trying to remove a `null` element, it didn't seem necessary. – Eran Jun 15 '17 at 10:36
  • Now, who's gonna report that to Oracle (and how)? :) – domsson Jun 15 '17 at 10:44
2

Ok, the Nullpointerexception thrown from remove method of TreeSet. Below is the source code of Treeset's removeAll() method

public boolean removeAll(Collection<?> c) {
167        boolean modified = false;
168
169        if (size() > c.size()) {
170            for (Iterator<?> i = c.iterator(); i.hasNext(); )
171                modified |= remove(i.next());
172        }

The removeAll() method internally calling remove() .Since you are performing with some null values , TreeSet's remove() method can't process it and hence the exception.

NullPointerException - if the specified element is null and this set uses natural ordering, or its comparator does not permit null elements

Suresh Atta
  • 120,458
  • 37
  • 198
  • 307
  • *and the specified collection does not permit null elements* which is the specified collection? The one being removed from or the paramater? – Scary Wombat Jul 19 '17 at 06:10
  • @ScaryWombat The one on which you called the removedAll(). – Suresh Atta Jul 19 '17 at 06:13
  • @ScaryWombat: "The specified collection" is the argument (whereas "this collection" is the object whose method is being invoked). – ruakh Jul 19 '17 at 06:15