Comparable和Comparator关于null的合同

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

从API :

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

另一方面, Comparator API在比较null时没有提到什么需要发生。 考虑下面一个采用Comparable的generics方法的尝试,并返回一个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的不成文规则?
  • 甚至不得不对包含null元素的List进行sorting是一个好主意,还是devise错误的确定标志?

Comparable不允许null因为:

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

对于所有对象ab where !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器做什么。

甚至不得不对包含空元素的List进行sorting是一个好主意,还是devise错误的确定标志?

从概念上来说,null意味着“什么都不是”,并且在列表中没有任何东西对我来说似乎很奇怪。 此外,Java列表合同规定

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

所以Java中的List实现甚至不需要支持null元素。 总而言之,如果您没有足够的理由将null放入列表中,请不要,如果您这样做,则testing它是否按预期工作。

甚至不得不对包含空元素的List进行sorting是一个好主意,还是devise错误的确定标志?

那么,列表中可能包含一个空对象可能没有意义,但是也许您的列表包含一个“业务对象”,您可以对业务对象的不同属性进行sorting,其中一些可能包含空值。

这是一个比较器可以接受的使用

BeanComparator允许你在一个业务对象中进行sorting,即使这个属性包含null,所以我不得不说它是一个可以接受的比较器的用法。