removeAll()时TreeSet中的NullPointerException

Collection.removeAll()的文档:

抛出: NullPointerException – 如果此collection包含一个或多个null元素且指定的collection不支持null元素(可选),或者指定的collection为null。

但是下面的代码仍然会抛出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); } } 

有人能帮我理解这种行为吗?

我猜Javadoc的条件是什么时候可能会被removeAll抛出NullPointerException是不准确的。

TreeSetremoveAll依赖于AbstractSet的实现。 该实现迭代了两组中较小的所有元素。

在你的代码片段中,这是包含null元素的HashSet 。 因此removeAll遍历HashSet并尝试从TreeSet删除它找到的每个元素。

但是,当尝试从uses natural ordering, or its comparator does not permit null elements集合中删除null元素uses natural ordering, or its comparator does not permit null elements时, remove TreeSet会抛出NullPointerException

总而言之, NullPointerException是由TreeSetremove()引起的,这在remove()的Javadoc中有解释:

抛出:

ClassCastException – 如果指定的对象无法与此set中当前的元素进行比较

NullPointerException – 如果指定的元素为null并且此set使用自然排序 ,或者其比较器不允许null元素

有趣的是,向HashSet添加一个元素将消除NullPointerException ,因为在这种情况下,两个Set将具有相同的大小,并且removeAll()的实现将迭代TreeSet的元素。

好的,从TreeSet的remove方法抛出Nullpointerexception 。 下面是Treeset的removeAll()方法的源代码

 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 } 

removeAll()方法在内部调用remove() 。由于你使用一些null值执行, TreeSet的remove()方法无法处理它,因此也无法处理exception。

NullPointerException – 如果指定的元素为null并且此set使用自然排序,或者其比较器不允许null元素