代码之家  ›  专栏  ›  技术社区  ›  user51

使用Comparator.NullsList时发生NullPointerException

  •  2
  • user51  · 技术社区  · 6 年前

    我有下面两个类的代码myrange和mycustomvalue-

    class MyRange {
        private Long id;
        private Double minValue;
        private Double maxValue;
    
        // getters and setters
        // equals, hashCode and toString
    
        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null || getClass() != obj.getClass())
                return false;
            MyRange other = (MyRange) obj;
            return Objects.equals(this.id, other.id) && 
                   Objects.equals(this.minValue, other.minValue) &&
                   Objects.equals(this.maxValue, other.maxValue);
        }
    }
    
    class MyCustomValue {
        private String value;
        private MyRange myrange;
    
        //getters and setters
        // equals, hashCode and toString
    
    }
    

    如果 value 是空的 MyCustomValue 我要最后一个。所以我写下比较器,如下所示

    public static final Comparator<MyCustomValue> externalMVComparator = (emv1, emv2) -> {
        if(emv1.getValue() != null && emv2.getValue() == null) {
            return -1;
        } else if (emv1.getValue() == null && emv2.getValue() != null) {
            return 1;
        } else {
            return myrangeMinValueComparator.compare(emv1, emv2);
        }
    }
    
    private static final Comparator<MyRange> minValueComparator =  Comparator.nullsLast(Comparator.comparingDouble(value -> value.getMinValue()));
    private static final Comparator<MyCustomValue> myrangeMinValueComparator = Comparator.nullsLast(Comparator.comparing(MyCustomValue::getMyrange, minValueComparator));
    

    上面的比较器工作正常。所以我决定改变 externalMVComparator 如下(即,使用 thenComparing 为了提高可读性)

    private static final Comparator<MyCustomValue> valueComparator = Comparator.nullsLast(Comparator.comparing(MyCustomValue::getValue));
    public static final Comparator<MyCustomValue> externalMVComparator2 = Comparator.nullsLast(valueComparator.thenComparing(myrangeMinValueComparator));
    

    但是用 externalMVComparator2 结果在 NullPointerException . 怎么了?我的代码有错?

    用于测试的代码-

    MyCustomValue emv1 = new MyCustomValue("v1", new MyRange(1L, 0.71, 0.79));
    MyCustomValue emv2 = new MyCustomValue(null, new MyRange(2L, 0.53, 0.65));
    MyCustomValue emv3 = new MyCustomValue("v2", new MyRange(3L, 0.28, 0.42));
    MyCustomValue emv4 = new MyCustomValue(null, new MyRange(4L, 0.06, 0.27));
    List<MyCustomValue> shuffledList1 = Arrays.asList(emv1, emv2, emv3, emv4);
    Collections.shuffle(shuffledList1);
    shuffledList1.sort(MyCustomValue.externalMVComparator2);
    Assert.assertEquals(shuffledList1, Arrays.asList(emv3, emv1, emv4, emv2));
    

    StackTrace错误-

        Exception in thread "main" java.lang.NullPointerException
        at java.util.Comparator.lambda$comparing$77a9974f$1(Comparator.java:469)
        at java.util.Comparator.lambda$thenComparing$36697e65$1(Comparator.java:216)
        at java.util.Comparators$NullComparator.compare(Comparators.java:83)
        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.Arrays$ArrayList.sort(Arrays.java:3895)
        at TestNullComparator.main(TestNullComparator.java:15)
    
    1 回复  |  直到 6 年前
        1
  •  4
  •   Misha    6 年前

    问题出在下面一行(我删除了 Comparator. 为清晰起见:

    Comparator<MyCustomValue> valueComparator = nullsLast(comparing(MyCustomValue::getValue));
    

    这个 Comparator 你做的会处理 null 价值观 MyCustomValue 类型。它不能处理 无效的 返回的 getValue . 您必须使用的2参数版本 Comparator.comparing 供应A 无效的 -值的安全比较器:

    valueComparator = comparing(MyCustomValue::getValue, nullsLast(naturalOrder()));
    

    上面将处理您实际希望排序的常见情况 value . 当我查看您的代码时,我认为您的意思是只使用 价值 对于 无效的 检查,否则不希望按它排序。如果是这样,您可以使用 nullsLast( (x,y) -> 0) 作为空安全的第二个参数 comparing 这将认为所有字符串都是相等的。您也可以使用 valueComparator = comparing(mcv -> mcv.getValue() == null) 因为 true 追求 false 按自然顺序排列,但这可能不太清楚。

    如果你还想处理 无效的 S的 MyCuppy值 你得把它包起来 nullsLast 再一次。