#java #optional
#java #тип параметра
Вопрос:
Это исходный фрагмент кода:
Set<StatuteType> statuteTypes = registration.getStudent().getStudentStatutesSet()
.stream()
.map(StudentStatute_Base::getType)
.collect(Collectors.toSet());
Я хочу обернуть все в необязательный, чтобы избежать нулевых указателей и всего остального. Если студент не существует или statutesSet не существует.
Что у меня есть:
Set<StatuteType> statuteTypes = Optional.of(registration)
.map(Registration_Base::getStudent)
.map(student -> student.getStudentStatutesSet())
.flatMap(Collection::stream)
.map(StudentStatute_Base::getType)
.collect(Collectors.toSet())
.orElse(null);
Возможно ли что-то подобное? Я хочу избежать нулевых проверок в этой цепочке, и если есть какой-либо null, просто верните простой null, а вместо этого получите исключение.
Обычно, я думаю, было бы логично использовать flatMap, как описано здесь, но в данном случае это не кажется правильным, потому что необязательный flatmap возвращает необязательный.
Комментарии:
1.Итак
registration
getStudent()
,getStudentStatutesSet()
иgetType
все могут вернутьсяnull
, и вы хотите их обработать?2.
Optional
не предназначен для использования таким образом. Не предполагается заменять проверки null в цепочке методов, как вы пытаетесь выполнить. Вместо этого используйте его в качестве возвращаемого типа, если у вас есть возможность изменить своиRegistration
Student
классы and . Если вас интересует этот подход, я мог бы написать ответ3.
.orElse(null)
создает нулевую проблему, от которой, по вашим словам, вы хотели избавиться. Вместо этого используйте.orElse(Collections.emptySet())
.4. Если вы хотите игнорировать возможные значения null, просто отфильтруйте поток:
.filter(Objects::nonNull)
5. @fps Я никому не доверяю. Я согласен с тем, что показано на экране в том месте видео, на которое вы ссылаетесь, но это когда у вас есть только один уровень. Представьте себе 5 уровней.
a.getB().getC().getD().getE()
. Какую альтернативуOptional#map
цепочке вы бы предложили? 5 уровней if-null-проверок? Я все еще думаю, что это допустимое использованиеOptional
. Как документация API, так и слова Стюарта МарксаOptional
, в первую очередь предназначены для типа возвращаемого метода. Это не исключает такого рода использования.
Ответ №1:
Вот простой способ сделать это:
Set<StatuteType> statuteTypes = Optional.ofNullable(registration)
.map(Registration_Base::getStudent)
.map(student -> student.getStudentStatutesSet())
.map(Collection::stream)
.orElseGet(Stream::empty) // Exit Optional, enter stream
.map(StudentStatute_Base::getType)
.collect(Collectors.toSet());
Однако это не приводит к набору null. Коллекции никогда не должны быть нулевыми, только пустыми. Я бы рекомендовал этот подход. Весь смысл использования Optional
объекта в том, чтобы вам никогда не приходилось иметь дело с нулевыми значениями.
Комментарии:
1. Идеальный. Но это должно быть .OrElse(Stream.empty()) иначе это не сработает.
2. Моя ошибка. Однако вы можете использовать
.orElseGet(Stream::empty)
. Это не приведет к инициализации потока, еслиOptional
значение не равно null.
Ответ №2:
Collection::stream
не возвращает an Optional
, поэтому вы не должны использовать flatMap
здесь. Вы должны продолжать использовать map
необязательный.
.map(Collection::stream)
дает вам Optional<Stream<Statute>>
. Похоже, вы пытаетесь вызвать методы потока map
и collect
для этого. Но вам нужно сначала вызвать Optional.map
, прежде чем вы сможете это сделать.
Вы также должны использовать Optional.ofNullable
if registration
может быть null:
Set<StatuteType> statuteTypes = Optional.ofNullable(registration)
.map(Registration_Base::getStudent)
.map(student -> student.getStudentStatutesSet())
.map(Collection::stream)
.map(x -> // Optional.map
x.map(StudentStatute_Base::getType) // Stream.map
.filter(Objects::nonNull) // I assume you want to filter out the statute types which are null?
.collect(Collectors.toSet())
)
.orElse(null);