我有一个带有几个“可选”(不是java.util.Optional)字段的类。我正在编写一个Lambda比较器,通过比较它们的属性子集来测试是否相等

我写

private final static Comparator<MyEntity> COMPARATOR_491 =
            comparing(MyEntity::getIsin)
             .thenComparing(MyEntity::getTMarketType)
             .thenComparing(nullsFirst(comparing(MyEntity::getIsoCode)))
             .thenComparing(MyEntity::getTaxRate)
             .thenComparing(nullsFirst(comparing(MyEntity::getEndDate)));
  • ISIN不为空
  • 市场类型不为空
  • 代码是否可以为空
  • 税率不为空
  • 结束日期可以为空

  • 问题是我经常收到NullPointerException。这是(几乎不可读)堆栈跟踪
    java.lang.NullPointerException: null
        at java.util.Comparator.lambda$comparing$77a9974f$1(Comparator.java:469) ~[?:1.8.0_51]
        at java.util.Comparator$$Lambda$40/221702765.compare(Unknown Source) ~[?:?]
        at java.util.Comparators$NullComparator.compare(Comparators.java:83) ~[?:1.8.0_51]
        at java.util.Comparator.lambda$thenComparing$36697e65$1(Comparator.java:217) ~[?:1.8.0_51]
        at java.util.Comparator$$Lambda$42/770739971.compare(Unknown Source) ~[?:?]
        at java.util.Comparator.lambda$thenComparing$36697e65$1(Comparator.java:216) ~[?:1.8.0_51]
        at java.util.Comparator$$Lambda$42/770739971.compare(Unknown Source) ~[?:?]
        at java.util.Comparator.lambda$thenComparing$36697e65$1(Comparator.java:216) ~[?:1.8.0_51]
        at java.util.Comparator$$Lambda$42/770739971.compare(Unknown Source) ~[?:?]
    

    我发现两个示例实体在结束日期方面有所不同。第一个实体具有非null属性,第二个实体具有null

    我认为当一个或两个参数为null时,nullsFirst比较器可以为null安全。

    我究竟做错了什么?

    最佳答案

    nullsFirst(…)返回的比较器返回一个比较器,该比较器处理要比较的一个或两个对象都是null的情况。

    因此,当您说nullsFirst(comparing(MyEntity::getIsoCode))时,如果两个MyEntity实例都不是null,则您将得到一个比较器来处理一个或两个getIsoCode实例均为null的情况,并根据其自然顺序比较MyEntity属性(不处理null值)。

    您想要实现的是comparing(MyEntity::getIsoCode, nullsFirst(naturalOrder())),指定用于比较属性值的null -safe比较器。 getEndDate属性也是如此。

    您可以将它与thenComparing融合为previousComparator.thenComparing(MyEntity::getIsoCode, nullsFirst(naturalOrder()))

    10-04 10:02