Можно ли вызвать два терминальных оператора у одного Stream в Java?

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

Ответ

Нет, нельзя. Поток (Stream) в Java может быть потреблен только один раз. После вызова любого терминального оператора (collect, forEach, count, findFirst и др.) поток считается закрытым. Попытка вызвать второй терминальный оператор приведет к IllegalStateException.

Пример ошибки:

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

stream.forEach(System.out::println); // Первый терминальный вызов — поток потреблен
stream.count(); // IllegalStateException: stream has already been operated upon or closed

Как выполнить несколько действий?

  1. Объединить в цепочке промежуточных операторов с одним терминальным:
    List<String> result = list.stream()
        .filter(s -> s.startsWith("a"))
        .map(String::toUpperCase)
        .collect(Collectors.toList()); // ОДИН терминальный оператор
  2. Создать новый поток для каждой терминальной операции:
    long count = list.stream().count(); // Поток 1
    List<String> collected = list.stream().collect(Collectors.toList()); // Поток 2

    Принцип: «Один поток — одно терминальное действие».