Как мне работать с нулевыми и дублирующимися значениями в компараторе Java 8?
У меня есть объект Photo
:
public class Photo {
@Id
private String id;
private LocalDateTime created;
private Integer poNumber;
}
poNumber может быть нулевым для некоторых фотографий или всех фотографий в наборе. Я хочу отсортировать набор фотографий в соответствии с poNumber, чтобы наименьшее значение poNumber появилось первым в отсортированном наборе. poNumber также может дублироваться в наборе. Если poNumber дублируется, то сортируйте в соответствии с созданным (самое раннее созданное фото появляется первым). Если poNumber - ноль, тогда сортируйте согласно созданному.
Я попробовал следующий код:
Set<Photo> orderedPhotos = new TreeSet<>(
Comparator.nullsFirst(Comparator.comparing(Photo::getPoNumber))
.thenComparing(Photo::getCreated));
for (Photo photo : unOrderedPhotos) {
orderedPhotos.add(photo);
}
Но он выдает NullPointerException
всякий раз, когда poNumber равен нулю. Если poNumber не равен нулю, он работает нормально. Как я могу решить эту проблему?
Ответы
Ответ 1
Вы можете использовать перегрузку 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));
Ответ 2
Нам нужно решение, которое превращает Function<>
в Comparator, но таким способом, который добавляет указанную проверку null
в цепочку.
И вот, где Александр отвечает на сцену: он создает Comparator
который отображает сравниваемую Photo
на сравнение Integer
, а затем добавляет Comparator, который, естественно, сначала упорядочивает эти Integer
с null
:
Comparator.comparing(Photo::getPoNumber, Comparator.nullsFirst(Comparator.naturalOrder()))
И этот компаратор затем связывается (для случая равенства) с другим компаратором, который рассматривает дату создания.
Ответ 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
Ответ 4
Это установит нулевые значения в начале
Integer getPoNumber() { return poNumber == null ? Integer.MIN_VALUE : poNumber };
Это поставит нулевые значения в конце
Integer getPoNumber() { return poNumber == null ? Integer.MAX_VALUE: poNumber };
В противном случае, реализуйте свой собственный компаратор для обработки нулевых значений