Можно ли передавать объект Stream в качестве аргумента метода в Java Stream API?

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

Ответ

Да, технически это возможно, но крайне не рекомендуется из-за одноразовой природы Stream.

Проблема: Stream в Java можно использовать (вызвать терминальную операцию) только один раз. После этого он считается потреблённым и любая последующая операция выбросит IllegalStateException.

Пример опасного кода:

public void process(Stream<String> stream) {
    long count = stream.count(); // Терминальная операция — stream "закрыт"
    stream.forEach(System.out::println); // IllegalStateException!
}

Stream<String> stream = Stream.of("A", "B", "C");
process(stream); // Вызовет исключение на втором действии внутри метода

Правильные подходы:

  1. Передавать источник данных (коллекцию, массив):
    public void process(Collection<String> data) {
        data.stream().forEach(System.out::println);
        data.stream().count(); // Безопасно, создаётся новый Stream
    }
  2. Передавать Supplier: Это самый гибкий и безопасный способ.

    public void process(Supplier<Stream<String>> streamSupplier) {
        // Каждый get() создаёт новый, независимый поток
        streamSupplier.get().forEach(System.out::println);
        streamSupplier.get().map(String::toUpperCase).forEach(System.out::println);
    }
    
    // Вызов
    List<String> list = Arrays.asList("A", "B", "C");
    process(() -> list.stream()); // Безопасная передача "фабрики" потоков

Вывод: Избегайте передачи Stream как аргумента, если только вы не контролируете его однократное использование внутри метода. Предпочитайте передачу источника данных или Supplier<Stream>.