【问题标题】:How do I deal with null and duplicate values in a Java 8 Comparator?如何处理 Java 8 比较器中的空值和重复值?
【发布时间】:2018-11-16 11:52:10
【问题描述】:

我有一个Photo 对象:

public class Photo {
    @Id
    private String id;
    private LocalDateTime created;
    private Integer poNumber;
}

poNumber 可以为部分照片或一组照片中的所有照片为空。我想根据 poNumber 对一组照片进行排序,使最低 poNumber 出现在排序后的集合中。 poNumber 也可能在集合中重复。如果 poNumber 重复,则根据创建的排序(最早创建的照片首先出现)。如果 poNumber 为 null 则根据 created 排序。

我尝试了以下代码:

Set<Photo> orderedPhotos = new TreeSet<>(
    Comparator.nullsFirst(Comparator.comparing(Photo::getPoNumber))
              .thenComparing(Photo::getCreated));

for (Photo photo : unOrderedPhotos) {
    orderedPhotos.add(photo);
}

但只要 poNumber 为空,它就会抛出 NullPointerException。如果 poNumber 不为空,那么它工作正常。我该如何解决这个问题?

【问题讨论】:

  • 带有poNumber = null 的元素应该去哪里?在该字段中具有非空值的元素之后还是之前?

标签: java java-8 comparator


【解决方案1】:

我们需要一种将Function&lt;&gt; 转换为比较器的解决方案,但以某种方式将上述null 检查添加到链中。

这就是Oleksandr's answer 进入场景的地方:它创建了一个Comparator,它将比较的Photo 映射到Integers 的比较,然后添加一个比较器,它自然地将这些Integers 与@ 排序987654328@s 先:

Comparator.comparing(Photo::getPoNumber, Comparator.nullsFirst(Comparator.naturalOrder()))

然后这个比较器与另一个考虑创建日期的比较器链接(对于相等的情况)。

【讨论】:

    【解决方案2】:

    您可以使用两个参数的Comparator.comparing 重载,例如:

    import static java.util.Comparator.*; // for the sake of brevity
    
    Set<Photo> orderedPhotos = new TreeSet<>(
        Comparator.comparing(Photo::getPoNumber, nullsFirst(naturalOrder()))
                  .thenComparing(Photo::getCreated));
    

    【讨论】:

      【解决方案3】:

      按照你写的方式,照片键可以是null,但没有别的。

      Comparator.nullsFirst( // Photo could be null.
          Comparator.comparing(Comparator.nullsFirst(Photo::getPoNumber)) // poNumber could be null.
                    .thenComparing(Comparator.nullsFirst(Photo::getCreated))) // created could be null
      

      如果其中任何一个不能是null,您可以删除Comparator.nullsFirst

      【讨论】:

      • “但只要 poNumber 为空,它就会抛出 NullPointerException。如果 poNumber 不为空,则工作正常。”没有提到created 可以为空。
      【解决方案4】:

      这会将空值放在开头

      Integer getPoNumber() { return poNumber == null ? Integer.MIN_VALUE : poNumber };
      

      这会将空值放在最后

      Integer getPoNumber() { return poNumber == null ? Integer.MAX_VALUE: poNumber };
      

      否则,实现您自己的比较器来处理空值

      【讨论】:

      • 我不喜欢Integer,所以在这种情况下会返回int。 ;)
      • 这是他正在使用的,但是是的... @ace , Integer.intValue();
      猜你喜欢
      • 1970-01-01
      • 2010-11-20
      • 2023-03-09
      • 2011-06-18
      • 2012-02-06
      • 2020-11-15
      • 1970-01-01
      • 1970-01-01
      • 2019-03-13
      相关资源
      最近更新 更多