带有null-safe-comparator

时间:2017-08-28 19:09:35

标签: java-8

我想要一个零安全比较器,但它不起作用:

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)

有什么问题?

3 个答案:

答案 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,即i1i2,但它们的字段为: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())                               
);