可比comparareto允许null,如Comparator nullsFirst或nullsLast



ComparableComparator上有无数的问题和答案,但似乎没有一个解决这个问题。

假设我有这个方法compare,它接受任意Comparable对a和b的实现,并返回比较值-1、0或1。

static <U,T extends Comparable<U>> int compare(T a, U b) {
return a.compareTo(b);
}

工作与任何Comparable都很好,很好。方法被整个企业的每个项目所采用。

jshell> compare(1, 2);
$1 ==> -1
jshell> compare("id", "hi");
$2 ==> 1

然后突然数据变了,我们开始有问题了。


jshell> compare(null, "hi");
|  Exception java.lang.NullPointerException: Cannot invoke "java.lang.Comparable.compareTo(Object)" because "<parameter1>" is null
|        at compare (#1:2)
|        at (#2:1)
jshell> compare(1, null);
|  Exception java.lang.NullPointerException: Cannot read field "value" because "anotherInteger" is null
|        at Integer.compareTo (Integer.java:1473)
|        at Integer.compareTo (Integer.java:71)
|        at compare (#1:2)
|        at (#3:1)

寻找其他SO问题的答案,他们都会重复文档所说的:

请注意,null不是任何类的实例,即使e.p equals(null)返回false, e.p areto (null)也会抛出NullPointerException。

这简直是不可接受的!我们的Comparator类有nullsFirstnullsLast这样的方法,那么我们如何在不改变方法名称和签名的情况下解决这个问题呢?我们希望空值小于非空值,当两者都为空时,它们应该被认为是相等的。此外,客户端非常挑剔,不会接受任何if = null或if (a == null)比较。

我们如何改变我们流行的比较方法,使其仍然接受任意两个包含null的Comparable,并产生以下返回值:

jshell> compare(1, 2);
$5 ==> -1
jshell> compare("id", "hi");
$6 ==> 1
jshell> compare(null, "hi");
$7 ==> -1
jshell> compare(1, null);
$8 ==> 1
jshell> compare(null, null);
$9 ==> 0

需要修改您的compare方法。改变这个:

static <U,T extends Comparable<U>> int compare(T a, U b) {
return a.compareTo(b);
}

:

static <U,T extends Comparable<U>> int compare(T a, U b) {
if (a == null) {
return (b == null) ? 0 : -1;
} else if (b == null) {
return +1;
} else {
return a.compareTo(b);
}
}

客户端特别不希望任何if = null或if (a == null)比较。为什么我们不能简单地使用Comparator.nullsFirst,因为它已经做了我们想要的?

因为它不工作。

(更正:实际上应该是@AndreyB。Panfilov评论了一个现已删除的回答:

return Comparator.nullsFirst(Comparator.<T>naturalOrder()).compare(a, b);

但这并没有使我对下一句话的看法无效

有时候客户的要求太愚蠢了,你不得不拒绝。你需要教育客户。认真对待。这符合他们的最大利益

但是如果你真的有一个客户坚持认为null字是撒旦的后代(或其他)…您可以使用Objects.isNull(javadoc)实现null检查。

这是实际的解决方案:改变一个现有的比较方法,它需要两个Comparables实现compareTo,也允许null比较,像Comparator.nullsFirst一样,不改变方法的名称或签名,不使用任何if语句。简单的?=)

当前方法:

static <U,T extends Comparable<U>> int compare(T a, U b) {
return a.compareTo(b);
}

就变成:

static <T extends Comparable<T>> int compare(T a, T b) {
return Comparator.nullsFirst(Comparator.<T>naturalOrder()).compare(a, b);
}

因为对于T extends Comparable<U>,我们有U extends T来生成U instanceof T,所以我们可以用U代替T,并且方法签名保持不变。

不需要null比较,也不需要重新发明一个完美的轮子。Java可以做你想做的事,它当然可以,你只需要愿意付出努力。

nJoy

最新更新