如何在Java 8 Comparator中处理null和重复值?

ace*_*ace 14 java comparator java-8

我有一个Photo对象:

public class Photo {
    @Id
    private String id;
    private LocalDateTime created;
    private Integer poNumber;
}
Run Code Online (Sandbox Code Playgroud)

对于某些照片或集合中的所有照片,poNumber可以为null.我想根据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);
}
Run Code Online (Sandbox Code Playgroud)

但是NullPointerException只要poNumber为null,它就会抛出一个.如果poNumber不为null,那么它可以正常工作.我该如何解决这个问题?

glg*_*lgl 9

我们需要一个解决方案,将其变为Function<>比较器,但是以一种将所述null检查添加到链中的方式.

这就是Oleksandr的答案进入场景的地方:它创建了一个Comparator映射Photo比较Integers的比较,然后添加一个Comparator,它自然地Integernulls 命令这些s :

Comparator.comparing(Photo::getPoNumber, Comparator.nullsFirst(Comparator.naturalOrder()))
Run Code Online (Sandbox Code Playgroud)

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


Ole*_*hov 8

您可以使用双参数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));
Run Code Online (Sandbox Code Playgroud)