Когда данные в Java Stream реально изменяются?

«Когда данные в Java Stream реально изменяются?» — вопрос из категории Java Core, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Данные в Java Stream изменяются (обрабатываются) только при вызове терминальной операции. Это называется ленивым (lazy) выполнением.

  • Промежуточные операции (например, map, filter, sorted) лишь описывают конвейер преобразований, но не выполняют их.
  • Терминальные операции (например, collect, forEach, reduce) запускают обработку всего конвейера.

Пример, демонстрирующий ленивость:

List<String> list = List.of("a", "b", "c");
Stream<String> stream = list.stream()
    .map(s -> {
        System.out.println("Mapping: " + s); // Сообщение выведется только после вызова collect
        return s.toUpperCase();
    }); // На этом этапе ничего не происходит

List<String> result = stream.collect(Collectors.toList()); // Терминальная операция — выполняются все преобразования
// В консоли будет:
// Mapping: a
// Mapping: b
// Mapping: c

Важное следствие: Stream является одноразовым (consumable). После вызова терминальной операции поток считается использованным, и повторная попытка его использования выбросит IllegalStateException.