Как положить в Optional<> null по результатам работы stream
Предположим, есть сущность Box
public class Box {
public int id;
public String name;
public Box(int id, String name) {
this.id = id;
this.name = name;
}
public Box(int id) {
this.id = id;
}
Мне приходит список этих коробок, и я должен узнать имя конкретной коробки (оно может быть null) Как я это делаю:
Box box1 = new Box(1, "1");
Box box2 = new Box(2);
List<Box> list = Arrays.asList(box1, box2);
Optional<String> boxName = list.stream()
.filter(b -> b.id == 2)
.map(b -> b.name).findAny(); //<-тута вот упадет
String name = boxName.orElse(null);
Получаю такую вот ошибку:
Exception in thread "main" java.lang.NullPointerException
at java.base/java.util.Objects.requireNonNull(Objects.java:221)
at java.base/java.util.Optional.<init>(Optional.java:107)
at java.base/java.util.Optional.of(Optional.java:120)
at java.base/java.util.stream.FindOps$FindSink$OfRef.get(FindOps.java:194)
at java.base/java.util.stream.FindOps$FindSink$OfRef.get(FindOps.java:191)
at java.base/java.util.stream.FindOps$FindOp.evaluateSequential(FindOps.java:150)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.findAny(ReferencePipeline.java:548)
at Main.main(Main.java:39)
Я знаю что можно решить задачку так:
Box box1 = new Box(1, "1");
Box box2 = new Box(2);
List<Box> list = Arrays.asList(box1, box2);
Box box = list.stream()
.filter(b -> b.id == 2).findAny().orElse(null);
String name = box != null ? box.name : null;
Но мне кажется, что просто чего-то не хватает в первом варианте.
Ответы (2 шт):
Автор решения: Roman-Stop RU aggression in UA
→ Ссылка
В Optional в принципе нельзя положить значение null. Можно только создать Optional.empty, т.е. отсутствие значения.
То, что вам нужно делается так:
Optional<String> boxName = list.stream()
.filter(b -> b.id == 2 && b.name != null)
.map(b -> b.name)
.findAny()
или так:
Optional<String> boxName = list.stream()
.filter(b -> b.id == 2)
.map(b -> b.name)
.filter(name -> name != null)
.findAny()
Автор решения: Nowhere Man
→ Ссылка
Почему бы не написать проще:
- найти бокс по идентификатору при помощи
Stream::findAny/Stream::findFirst, получивOptional<Box> - преобразовать Box -> String при помощи
Optional::map, получивOptional<String>, при этомnameможет бытьnullдля некоторого бокса. - для случая, когда бокс не найден, вернуть
nullдля имени
String boxName = list.stream() // Stream<Box>
.filter(b -> b.id == 2) // Stream<Box>
.findAny() // Optional<Box>
.map(b -> b.name) // Optional<String> - уже берется name
.orElse(null); // если не найден бокс, ТОЖЕ будет null