Как использовать компаратор с несколькими условиями при обработке исключения нулевого указателя

#java #lambda #java-stream #comparator

Вопрос:

Я не использую лямбды, и мне очень трудно передавать и изменять значение атрибута, называемого статусом, в зависимости от некоторых условий.

Список тестов содержит список элементов типа Testdto.

 MasterDto {
    List<TestDto> testListContent;
}
    
TestDto {
    Long id;
    @NotNull
    LocalDate startDate; /// This is not nullable
    LocalDate endDate; // This is nullable. Hence we have to handle null pointer exceptions.
    String status;
}
 

Изначально все значения статуса являются либо "Inactive" или "Future" или "Expired" .

Я хочу изменить значение статуса ОДНОГО объекта "ACTIVE" на тот, чей статус в настоящее "Inactive" время и чья дата вступления в силу является самой последней.

Если существует несколько объектов, даты вступления в силу которых являются самыми последними и равными, мы должны выбрать объект, значение даты окончания которого выше. ( Endate является недействительным, поэтому мы должны избегать исключения nullpointer здесь)

Если даты окончания этих объектов также совпадают ИЛИ равны НУЛЮ, мы можем выбрать первый из них в списке.

Вот что я придумал до сих пор

 masterDtos.gettestListContent()
    .stream()
.max(Comparator.comparing(TestDto::getStartDate)
.thenComparing(
    Comparator.nullsLast(
    Comparator.nullsLast(TestDto::getEndDate)
.get().setStatus(ACTIVE_STATUS);
 

Комментарии:

1. Пожалуйста, приведите пример, ввод и ожидаемый результат, спасибо.

2. Обратите внимание, что использование get() без проверки наличия опасно и приведет к сбою, если аргумент не существует. Воспользуйся ifPresent(do-> dto.setStatus(ACTIVE_STATUS)) .

Ответ №1:

В исходном коде необходимо рассмотреть несколько моментов:

  1. Comparator::nullsLast применяется к другому компаратору , например Comparator.naturalOrder , не к ссылке на метод.
  2. Следует использовать Optional::ifPresent для изменения состояния соответствующего элемента в списке, если он найден.

Таким образом, код должен выглядеть следующим образом:

 public static void activateLastInactive(List<TestDto> data) {
    data.stream()
        .filter(t -> "Inactive".equalsIgnoreCase(t.status))
        .max(
                Comparator.comparing(TestDto::getStartDate)
                          .thenComparing(TestDto::getEndDate, Comparator.nullsLast(Comparator.naturalOrder()))
        )
        .ifPresent(t -> t.setStatus("Active"));
    System.out.println("After: "   data);
}
 

Тесты

 List<TestDto> data = Arrays.asList(
        new TestDto(1L, LocalDate.of(2021, 1, 1), null, "Active"),
        new TestDto(2L, LocalDate.of(2021, 8, 8), LocalDate.of(2021, 9, 1), "Inactive"),
        new TestDto(3L, LocalDate.of(2021, 8, 8), null, "Inactive"),
        new TestDto(4L, LocalDate.of(2021, 8, 8), null, "Inactive")
) ;

System.out.println("Before: "   data);
activateLastInactive(data);

activateLastInactive(data);

activateLastInactive(data);
 

Выход

 Before: [TestDto(id=1, startDate=2021-01-01, endDate=null, status=Active), TestDto(id=2, startDate=2021-08-08, endDate=2021-09-01, status=Inactive), TestDto(id=3, startDate=2021-08-08, endDate=null, status=Inactive), TestDto(id=4, startDate=2021-08-08, endDate=null, status=Inactive)]

After: [TestDto(id=1, startDate=2021-01-01, endDate=null, status=Active), TestDto(id=2, startDate=2021-08-08, endDate=2021-09-01, status=Inactive), TestDto(id=3, startDate=2021-08-08, endDate=null, status=Active), TestDto(id=4, startDate=2021-08-08, endDate=null, status=Inactive)]
// id 3 activated

After: [TestDto(id=1, startDate=2021-01-01, endDate=null, status=Active), TestDto(id=2, startDate=2021-08-08, endDate=2021-09-01, status=Inactive), TestDto(id=3, startDate=2021-08-08, endDate=null, status=Active), TestDto(id=4, startDate=2021-08-08, endDate=null, status=Active)]
// id 4 activated

After: [TestDto(id=1, startDate=2021-01-01, endDate=null, status=Active), TestDto(id=2, startDate=2021-08-08, endDate=2021-09-01, status=Active), TestDto(id=3, startDate=2021-08-08, endDate=null, status=Active), TestDto(id=4, startDate=2021-08-08, endDate=null, status=Active)]
// id 2 activated
 

Ответ №2:

Ты уже близко. Вы должны звонить nullLast только один раз. Обратите внимание, что nullsLast принимает в качестве аргумента другой компаратор, а именно Компаратор для вызова, если и только если оба сравниваемых значения не являются нулевыми.

 masterDtos.gettestListContent()                                 // correct
    .stream()                                                   // correct
    .max(                                                       // correct
        Comparator.comparing(TestDto::getStartDate)             // correct
        .thenComparing(                                         // correct
            TestDto::getEndDate,                                // compare using...
            Comparator.nullsLast(Comparator.naturalOrder())     // ...null-safe comparator
        )
    )
.get().setStatus(ACTIVE_STATUS);
 

Комментарии:

1. Но проверка даты окончания должна выполняться только в том случае, если две даты вступления в силу являются недавними и равными. в противном случае мы не должны проверять даты окончания. Где мы это делаем ?

2. @AlexRudenko Ты прав. Исправлено.