#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:
В исходном коде необходимо рассмотреть несколько моментов:
Comparator::nullsLast
применяется к другому компаратору , напримерComparator.naturalOrder
, не к ссылке на метод.- Следует использовать
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 Ты прав. Исправлено.