← Назад к вопросам

Что произойдет если один из элементов Stream будет null?

2.7 Senior🔥 81 комментариев
#Stream API и функциональное программирование#Многопоточность

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Null элементы в Stream: проблемы и решения

Обработка null значений в Stream API — это частая источник ошибок и неожиданного поведения. Поведение зависит от того, на каком этапе обработки Stream встречается null, и какие операции применяются.

Что произойдет при null в Stream

1. NullPointerException при промежуточных операциях:

Если один из элементов null, и к нему применяется операция, которая вызывает методы объекта, получится NullPointerException:

List<String> list = Arrays.asList("a", "b", null, "c");
Stream<String> stream = list.stream();

// NullPointerException будет выброшена здесь
stream.map(String::toUpperCase)
      .forEach(System.out::println);

Этот код упадёт с ошибкой на третьем элементе, когда попытается вызвать toUpperCase() на null.

2. Поведение filter():

Метод filter() ожидает Function, которая возвращает boolean. Если внутри filter пытаться вызвать метод на null, также получится NullPointerException:

List<String> list = Arrays.asList("hello", null, "world");

// NullPointerException в filter
stream.filter(s -> s.length() > 3)
      .forEach(System.out::println);

Правильные подходы к обработке null

Подход 1: Отфильтровать null значения в начале

Самый простой и рекомендуемый способ — удалить null элементы на начальном этапе:

List<String> list = Arrays.asList("a", "b", null, "c");

list.stream()
    .filter(Objects::nonNull)  // Оставляем только не-null элементы
    .map(String::toUpperCase)
    .forEach(System.out::println);

// Вывод: A B C

Подход 2: Использование Optional

Для более сложных случаев можно оборачивать значения в Optional:

List<String> list = Arrays.asList("hello", null, "world");

list.stream()
    .map(Optional::ofNullable)  // Обертка в Optional
    .filter(Optional::isPresent)
    .map(Optional::get)
    .map(String::toUpperCase)
    .forEach(System.out::println);

// Вывод: HELLO WORLD

Или более элегантно с flatMap:

list.stream()
    .flatMap(s -> s != null ? Stream.of(s) : Stream.empty())
    .map(String::toUpperCase)
    .forEach(System.out::println);

Подход 3: Проверка null в lambda выражении

List<String> list = Arrays.asList("hello", null, "world");

list.stream()
    .filter(s -> s != null && s.length() > 3)
    .map(String::toUpperCase)
    .forEach(System.out::println);

// Вывод: HELLO WORLD

Специфика collect() с null

List<String> list = Arrays.asList("a", "b", null, "c");

// Здесь null будет добавлен в результирующий список
List<String> result = list.stream()
    .collect(Collectors.toList());

System.out.println(result); // [a, b, null, c]

Если нужно исключить null при collect:

List<String> result = list.stream()
    .filter(Objects::nonNull)
    .collect(Collectors.toList());

System.out.println(result); // [a, b, c]

Обработка null в terminal операциях

forEach():

// Если элемент null, consumer будет вызван с null
list.stream()
    .forEach(s -> {
        if (s != null) {
            System.out.println(s.toUpperCase());
        }
    });

reduce():

Optional<String> result = list.stream()
    .filter(Objects::nonNull)
    .reduce((a, b) -> a + "," + b);

result.ifPresent(System.out::println);

Best Practices

1. Всегда проверяй null в начале пайплайна:

list.stream()
    .filter(Objects::nonNull)  // Первое, что делаем
    .map(String::toUpperCase)
    .forEach(System.out::println);

2. Используй Optional для представления отсутствия значения:

Optional<String> maybeValue = Optional.ofNullable(nullableValue);
maybeValue.ifPresent(value -> process(value));

3. Документируй, может ли Stream содержать null:

/**
 * Возвращает stream строк, может содержать null элементы
 */
public Stream<String> getNames() { ... }

4. При создании Stream убедись, что нет null:

List<String> list = new ArrayList<>();
// list.add(null);  // Избегай этого
Stream<String> stream = list.stream();

Заключение

Null элементы в Stream требуют явной обработки. Стандартный подход — использовать filter(Objects::nonNull) в начале обработки. Это делает код более читаемым, безопасным и предсказуемым. Java Stream API не допускает null по дизайну, поэтому необходимо контролировать их наличие перед обработкой.

Что произойдет если один из элементов Stream будет null? | PrepBro