关于null的可比较和比较者合同

时间:2010-05-18 15:22:37

标签: java generics null comparator comparable

Comparable合同指定e.compareTo(null)必须抛出NullPointerException

来自the API

  

请注意,null不是任何类的实例,即使e.compareTo(null)返回NullPointerExceptione.equals(null)也应该抛出false

另一方面,Comparator API没有提及在比较null时需要发生什么。考虑以下尝试采用Comparable的通用方法,并为其Comparator作为最小元素返回null

static <T extends Comparable<? super T>> Comparator<T> nullComparableComparator() {
   return new Comparator<T>() {
      @Override public int compare(T el1, T el2) {
         return
            el1 == null ? -1 :
            el2 == null ? +1 :
            el1.compareTo(el2);
      }
   };
}

这允许我们执行以下操作:

List<Integer> numbers = new ArrayList<Integer>(
   Arrays.asList(3, 2, 1, null, null, 0)
);
Comparator<Integer> numbersComp = nullComparableComparator();
Collections.sort(numbers, numbersComp);
System.out.println(numbers);
// "[null, null, 0, 1, 2, 3]"

List<String> names = new ArrayList<String>(
   Arrays.asList("Bob", null, "Alice", "Carol")
);
Comparator<String> namesComp = nullComparableComparator();
Collections.sort(names, namesComp);
System.out.println(names);
// "[null, Alice, Bob, Carol]"

所以问题是:

  • 这是Comparator的可接受使用,还是违反了有关比较null和投掷NullPointerException的不成文规则?
  • 甚至不得不对包含List元素的null进行排序,或者这是设计错误的确定标志是不是一个好主意?

3 个答案:

答案 0 :(得分:25)

Comparable不允许null仅因为:

a.compareTo(b) == -b.compareTo(a)

适用于所有对象ab !a.equals(b)。更具体地说:

a.equals(b) ? b.equals(a) && a.compareTo(b) == 0 &&
                  b.compareTo(a) == 0 && a.hashCode() == b.hashCode()
            : !b.equals(a) && a.compareTo(b) != 0 &&
                  a.compareTo(b) == -b.compareTo(a)

必须评估为true以满足相关合同。

所以不允许null,因为你不能这样做:

null.compareTo(a)

Comparator更灵活,因此处理null是特定于实现的问题。支持与否,具体取决于您希望Comparator做什么。

答案 1 :(得分:8)

  

甚至不得不对包含null元素的List进行排序,或者这是设计错误的确定标志是不是一个好主意?

从概念上讲,null意味着“没有”,并且在列表中放置任何内容对我来说都很奇怪。此外,Java List合同声明了

  

某些列表实现对它们可能包含的元素有限制。例如,某些实现禁止null元素

因此,甚至不需要Java中的List实现来支持null元素。总而言之,如果您没有充分的理由将null放入列表中,请不要,如果您这样做,请测试它实际上是否按预期工作。

答案 2 :(得分:4)

  

甚至不得不这样做   对包含null元素的List进行排序,   或者这是设计的确定标志   错误?

嗯,列表包含空对象可能没有意义,但是您的List可能包含“业务对象”,您可以对业务对象的不同属性进行排序,其中一些属性可能包含空值。

  

这是否可以接受?   比较

BeanComparator允许您对业务对象中的某个属性进行排序,即使该属性包含null,因此我不得不说这是一个可接受的比较器使用。