Java8 空安全比较

问题描述 投票:0回答:2

比较两种产品时遇到问题。我想比较它们各自的年份(可选)属性。但只要该属性为 null,就会抛出 NPE。我认为使用 Comparator.nullsLast(..) 我可以处理空值...但看来我要么误解了它的工作原理,要么代码有问题。我需要更改什么才能使这项工作对 null 友好?

@Override
public int compare(IProduct product1, IProduct product2) throws ProductComparisonException {

    Comparator<IShopProduct> comparator =
        Comparator.nullsLast(Comparator.comparing(IShopProduct::getVintage));

    return comparator.compare((IShopProduct)product1.getProvidedProductData(),
                              (IShopProduct)product2.getProvidedProductData());
}

提前致谢

java comparator comparable
2个回答
8
投票

应该是

Comparator<IShopProduct> comparator = 
            Comparator.comparing( IShopProduct::getVintage, 
                             Comparator.nullsLast(Comparator.naturalOrder()));

Comparator.nullsFirst()/nullsLast()
考虑空值大于/小于非空对象

编辑

这是 Comparator.comparing() 的实现:

public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
        Function<? super T, ? extends U> keyExtractor)
{
    Objects.requireNonNull(keyExtractor);
    return (Comparator<T> & Serializable)
        (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
}

如您所见,它调用

keyExtractor.apply(c1).compareTo()
,因此如果
keyExtractor.apply(c1)
null

,它将抛出 NPE

我建议的代码使用以下函数:

public static <T, U> Comparator<T> comparing(
        Function<? super T, ? extends U> keyExtractor,
        Comparator<? super U> keyComparator)
{
    Objects.requireNonNull(keyExtractor);
    Objects.requireNonNull(keyComparator);
    return (Comparator<T> & Serializable)
        (c1, c2) -> keyComparator.compare(keyExtractor.apply(c1),
                                          keyExtractor.apply(c2));
}

基本上它会提取值,然后将比较值传递给

Comparator

这些值将传递到

naturalOrder()
比较器,该比较器解析为
value1.compareTo(value2)
。通常它会抛出 NPE,但我们用
Comparator.nullsLast
包裹它,它有特殊的
null
处理程序。


4
投票

如果传入的密钥提取器函数是 null 或提取的属性是

null
,则
comparing
方法的重载将引发异常。既然您提到
vintage
属性有时可能是
null
那么这就是 NullPointerException 的原因。

解决该问题的另一种方法是使用此比较器:

 Comparator<IShopProduct> comparator = 
      Comparator.comparing(IShopProduct::getVintage,
                Comparator.nullsLast(naturalOrder()));

密钥提取器即

IShopProduct::getVintage
是用于提取排序密钥的函数。

键比较器即

Comparator.nullsLast(Comparator.naturalOrder())
用于比较排序键。

Comparator.naturalOrder()
这里只是返回一个比较器,以自然顺序比较
Comparable
对象。

© www.soinside.com 2019 - 2024. All rights reserved.