【问题标题】:Java8 Null-safe comparisonJava8 Null 安全比较
【发布时间】:2018-05-07 13:24:03
【问题描述】:

比较两种产品时遇到问题。我想比较他们每个人的年份(可选)属性。但是只要这个属性为空,就会抛出一个 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());
}

提前致谢

【问题讨论】:

  • product1.getProvidedProductData() 是否有可能返回 null ?
  • 请查看标准 java 风格指南。如果人们不被特殊的造型问题分心,他们将更有可能帮助你。特别是不必要的空格和行太长的事实,我必须水平滚动

标签: java comparator comparable


【解决方案1】:

应该是

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

Comparator.nullFirst()/nullLast() 认为空值大于/小于非空对象

编辑

这是 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

这些值将传递给解析为value1.compareTo(value2)naturalOrder() 比较器。通常它会抛出 NPE,但我们用 Comparator.nullLast 包裹它,它有特殊的 null 处理程序。

【讨论】:

  • 谢谢!为什么我需要 naturalOrder 作为第二个参数?
【解决方案2】:

如果传入的键提取器函数为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 对象。

【讨论】:

    猜你喜欢
    • 2014-03-07
    • 1970-01-01
    • 2023-03-31
    • 1970-01-01
    • 2022-07-02
    • 2020-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多