У меня есть список объектов, которые содержат несколько свойств, одно из которых - LocalDate. Я хочу найти в этом списке объект с самой последней датой.

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

list.stream().filter( object -> object.getId() == id
&& object.getCancelDate() == null 
&& object.getEarliestDate() != null)
.min( Comparator.comparing( LocalDate::toEpochDay )
.get();

Это дает мне «Нестатический метод нельзя ссылаться из статического контекста» для функции Comparator.

Я рассмотрел возможность создания карты только дат из отфильтрованных объектов и до сих пор придумал что-то вроде этого.

list.stream().filter( object -> object.getId() == id
&& object.getCancelDate() == null 
&& object.getEarliestDate() != null)
.map( data -> data.getEarliestDate() )
.collect( Collectors.toList() )

И я не совсем уверен, что делать дальше и сработает ли это.

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

Обновить

Спасибо за ответ. Я обновил свой код Optional<YourObject> recentObject = list.stream().filter(object -> object.getId() == id && object.getCancelDate() == null && object.getEarliestDate() != null) .max(Comparator.comparing(s -> s.getEarliestDate().toEpochDay()));

Теперь я получаю сообщение об ошибке компилятора Несовместимые типы.

Required:Optional<MyClass>
Found:Optional<capture<? extends MyClass>>

Этот метод расширяет MyClass, поэтому в объявлении типа для Optional мне нужно сделать что-то вроде MyClass.class?

Обновление 2 Спасибо @Hogen за помощь в исправлении ошибки компилятора, добавив в конце .map (). Вот как это выглядело после изменения.

Optional<MyClass> date = 
list.stream().filter(object -> object.getId() == id &&
object.getCancelDate() == null &&
object.getEarliestDate() != null)
.max(Comparator.comparing( s -> s.getEarliestDate()
.toEpochDay())).map(Function.identity());

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

Optional<LocalDate> mostRecentDate = list.stream()
.filter(data -> data.getId() == id && data.getCancelDate() == null)
.map(MyObject::getEarliestDate)
.filter(Objects::nonNull)
.max(LocalDate::compareTo);
4
acousticarmor 11 Дек 2018 в 18:40

2 ответа

Лучший ответ

Помещаем это в ответ для наглядности. Основываясь на ответе @ nullpointer и предложении @ Holger, я смог придумать два следующих решения.

Решение 1

Optional<MyClass> mostRecentDate = list.stream()
    .filter(myObject -> myObject.getId() == id &&
     myObject.getCancelDate() == null && myObject.getEarliestDate() != null)
    .max(Comparator.comparing( s -> s.getEarliestDate()
    .toEpochDay())).map(Function.identity());

Решение 2

LocalDate mostRecentDate = list.stream()
    .filter(myObject -> myObject.getId() == id && myObject.getCancelDate() == null)
    .map(MyObject::getEarliestDate)
    .filter(Objects::nonNull)
    .max(LocalDate::compareTo)
    .orElse(null);

Оба решения работают, но второе решение, на мой взгляд, чище и менее двусмысленно. Он удаляет код .map (Function.identity ()), который на самом деле ничего не делает, как указал @Holgen, используя новый Справочник по методам ::. Он также фильтрует список объектов и отображает даты в новый список, который затем использует .max () с методом compareTo () вместо пользовательской функции. Я считаю настраиваемую функцию и бесполезный код беспорядочными и для любого, кто читает код, может сделать их менее понятными.

Обратите внимание, что во втором решении я также удалил необязательный класс. Использование .orElse () удовлетворяет возвращению фактического класса LocalDate вместо параметра из потока.

Спасибо за помощь всем, и я надеюсь, что этот ответ поможет другим.

1
acousticarmor 12 Дек 2018 в 20:24

Вы в основном ищете:

Optional<YourObject> recentObject = list.stream()
        .filter(object -> object.getId() == id && object.getCancelDate() == null && object.getEarliestDate() != null)
        .max(Comparator.comparing(YourObject::getEarliestDate)); // max of the date for recency

Из LocalDate.compareTo

Сравнивает эту дату с другой датой. Сравнение в первую очередь основано на на дату, от самого раннего до последнего . Это «согласуется с равными», как определено Comparable.

4
Naman 11 Дек 2018 в 16:15