Can't I put a null in a SortedSet?

9

我认为 null 是允许在 Set 中使用的。
那么为什么以下代码会出错:

SortedSet<Integer> set = new TreeSet<Integer>();  
set.add(null);  
set.add(1);  //--->Line indicated by exception  

以下异常信息是什么意思?
在主线程中出现异常java.lang.NullPointerException,在未知源处的java.lang.Integer.compareTo方法中,java.util.TreeMap.put和java.util.TreeSet.add方法中调用了两次java.lang.Integer.compareTo方法。
4个回答

20

可以这样做。但您需要提供自己的Comparator,以处理将null与集合中的其他内容进行比较时的情况。应用自然排序时,Java对象不知道如何将自己与null进行比较。反过来,null也不知道如何将自己与任何对象进行比较,因为您不能调用null.compareTo(object)

这样一个“null-safe” Comparator 的示例实现可以在apache的commons-collections库中找到。请查看NullComparator。您可以像这样使用它:

// Unfortunately no support for Java generics yet, in commons-collections
@SuppressWarnings("unchecked")
SortedSet<Integer> set = new TreeSet<Integer>(new NullComparator());  
set.add(null);  
set.add(1);

@Lukas Eder,我们能否对TreeMap也做同样的事情?在Java 7中,TreeMap和TreeSet都有所改变(http://bugs.java.com/view_bug.do?bug_id=5045147)。 - Aashutosh Shrivastava
@AashutoshShrivastava:我认为最好在新的Stack Overflow问题中回答这个问题。请随意创建一个。 - Lukas Eder
感谢@Lukas Eder。我正在使用NullComparator(),就像你上面提到的一样,它很好用。TreeMap<Integer, String> tree1 = new TreeMap<>(new NullComparator()); tree1.put(null, "aashu"); - Aashutosh Shrivastava

6

TreeSet的API(http://docs.oracle.com/javase/6/docs/api/java/util/TreeSet.html#add(E))中提到,如果使用自然排序或其比较器不允许null元素,则add方法将抛出NPE:

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

因此,如果要存储null,您必须提供一个可以处理这个问题并知道null在0或所有其他值中所处位置的比较器。


2

不需要创建比较器,你可以创建自己的“null”值。

static final Integer NULL = Integer.MIN_VALUE;

set.add(NULL):

2
这可能是一种不可接受的方法,因为所有整数值都有意义。如果使用的数字限于特定范围,则此方法可能是可接受的。 - Zéychin
2
MIN_VALUE很少有用,因为它具有奇怪的属性,例如x == -x && x != 0 ;) 并不经常需要每个int值,但是使用Long作为替代可能是一个选项。 - Peter Lawrey
哈哈,我从来没有想过 x == -x 对于 MIN_VALUE 的情况。当二进制补码不是你的主要领域时,这真的很令人惊讶... - Lukas Eder
2
对于Long.MIN_VALUE和Character.MIN_VALUE(它是0 ;)),但不适用于Short.MIN_VALUE、Byte.MIN_VALUE、Float.MIN_VALUE或Double.MIN_VALUE。 - Peter Lawrey
1
你总是用这些神秘的Java技巧让我惊叹不已,而你不断地发布它们。 - Lukas Eder
1
@LukasEder 谢谢,我会把它当作是一种赞美。 :) - Peter Lawrey

0
你不能将空值插入到TreeSet中。从JDK 1.7开始,TreeSet不再接受null值。将null值插入到TreeSet中会抛出NullPointerException异常,原因是在插入null时,它会与现有元素进行比较,而null无法与任何值进行比较。在JDK 1.6之前,第一个元素可以是null,但是任何更多的null元素都会导致NullPointerException异常。
如果必须添加null,则必须编写自己的自定义比较器来处理null,或者使用commons-collections提供的NullComparator()。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接