Имеется список элементов класса Event.
@Data
@AllArgsConstructor
public class Event {
private Long id;
private String nameRu;
private String nameEn;
}
Я хочу получить значение одного поля из события (любого из объектов).
Event event1 = new Event(1, null, null);
Event event2 = new Event(2, null, null);
List<Event> events = new ArrayList<>();
events.add(event1);
events.add(event2);
int languageId = 1;
String name = events.stream().map(s -> {
if (languageId == 1)
return s.getNameEn();
else if (languageId == 2)
return s.getNameRu();
else return s.getNameEn();
}).findAny().orElse(null);
Но если в каждом элементе это поле имеет значение null, то функцияstream.map() возвращает значение null (но она должна возвращать поток с некоторым количеством значений null), а вызов findAny() выдает исключение NullPointerException.
Два вопроса:
Пожалуйста, прочитайте документацию по findAny() docs.oracle.com/javase/8/docs/api/java/util/stream/… Особенно строку NullPointerException - if the element selected is null
это не map()
, возвращающий ноль! findAny()
, как описано в , выдаст исключение NullPointerException, если выбранный элемент null
(что, очевидно, имеет место, поскольку Event
создаются со строками null
) - трассировка стека должна ясно показывать, что findAny
действительно выполняется
Зачем вы проверяете languageId == 1
, когда все, что вы делаете, — это то же самое, что и запасной вариант? Просто .map(s -> languageId == 2? s.getNameRu(): s.getNameEn())
сделает то же самое.
Согласно JavaDoc это ожидаемое поведение:
/**
* Returns an {@link Optional} describing some element of the stream, or an
* empty {@code Optional} if the stream is empty.
*
* <p>This is a <a href = "package-summary.html#StreamOps">short-circuiting
* terminal operation</a>.
*
* <p>The behavior of this operation is explicitly nondeterministic; it is
* free to select any element in the stream. This is to allow for maximal
* performance in parallel operations; the cost is that multiple invocations
* on the same source may not return the same result. (If a stable result
* is desired, use {@link #findFirst()} instead.)
*
* @return an {@code Optional} describing some element of this stream, or an
* empty {@code Optional} if the stream is empty
* @throws NullPointerException if the element selected is null
* @see #findFirst()
*/
Optional<T> findAny();
@throws NullPointerException if the element selected is null
Чтобы это исправить, вы должны отфильтровать нулевые элементы следующим образом:
.map(s -> ... )
.filter(Objects::nonNull)
.findAny()
.orElse(null);
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
map() возвращает поток, но вы использовали .findAny()
, который дает вам NPE.
Вы можете применить фильтр перед .findAny()
, который удалит все нулевые значения,
Optional<String> name = events.stream().map(s -> {
if (languageId == 1)
return s.getNameEn();
else if (languageId == 2)
return s.getNameRu();
else return s.getNameEn();
})
.filter(Objects::nonNull)
.findAny();
ну, вы видели это "orElse(null);" часть? Кроме того, вы заметили, что вы ввели ноль для каждого отдельного варианта языка?