我想要一个零安全比较器,但它不起作用:
Comparator<Item> sort_high = (i1, i2)-> Double.compare(i2.getUser().getValue(), i1.getUser().getValue());
items.sort(Comparator.nullsFirst(sort_high));
但是,如果item.getUser()。getValue()(或item.getUser())为null,我会得到一个NPE。
at Item.lambda$1(Item.java:270)
at java.util.Comparators$NullComparator.compare(Comparators.java:83)
at java.util.TimSort.countRunAndMakeAscending(TimSort.java:355)
at java.util.TimSort.sort(TimSort.java:220)
at java.util.Arrays.sort(Arrays.java:1438)
at java.util.List.sort(List.java:478)
有什么问题?
答案 0 :(得分:3)
nullsFirst
将处理空Item
s(&#34; i1
&#34;),但一旦找到两个有效对象,您的Comparator
就是调用,您需要处理内部null
引用。
在您的情况下,您可以使用以下内容:
items.sort(
Comparator.nullsFirst(
Comparator.comparing(Item::getUser,
Comparator.nullsFirst(Comparator.comparingDouble(User::getValue))
)
)
);
(假设getValue()
返回double
)
但我几乎不推荐这种错综复杂的代码。
答案 1 :(得分:2)
Comparator.nullsFirst()
并不意味着NullPointerException
方法中引发的任何compare()
都会被捕获。
它表示null
比较对象始终小于非null
比较对象,如果两者都是null
,则认为它们相等。
<T> Comparator<T> java.util.Comparator.nullsFirst(Comparator<? super
T> comparator)
返回一个空值友好的比较器,将null视为小于 非空。当两者都为空时,它们被认为是相等的。如果两者都是 非null,指定的Comparator用于确定顺序。如果 指定的比较器为null,然后返回比较器 认为所有非空值都相等。
在你的情况下:
Comparator<Item> sort_high = (i1, i2)-> Double.compare(i2.getUser().getValue(), i1.getUser().getValue());
比较对象不是null
,即i1
或i2
,但它们的字段为:i1.getUser()
或i2.getUser()
。
您没有直接使用Comparator.nullsFirst()
的良好用例
作为解决方法,只要两个比较对象中的一个显示User
字段,您就可以使用它来比较compare()
实施中的null User
字段。
我认为在处理自己null
案例和代码的可读性之间是一个很好的权衡:
private Comparator<User> comparatorUserNullFirst = Comparator.nullsFirst(Comparator.comparingDouble(User::getValue));
Comparator<Item> sortHigh = (i1, i2) -> {
if (i1.getUser() == null || i2.getUser() == null) {
return comparatorUserNullFirst.compare(i1.getUser(), i2.getUser());
}
return Double.compare(i2.getUser().getValue(), i1.getUser().getValue());
};
答案 2 :(得分:0)
另一种可能性,即稍微更具可读性但不区分项目为空和具有用户为空的项目如下:
Comparator<Item> sortLow = Comparator.comparing(item -> Optional.ofNullable(item)
.map(Item::getUser)
.map(User::getValue)
.orElse(null),
Comparator.nullsFirst(Comparator.naturalOrder())
);