Ответ
Операции в Stream API делятся на два типа, которые кардинально отличаются по своему поведению и назначению в конвейере обработки данных.
Промежуточные операции (Intermediate Operations):
- Ленивые (Lazy): Не выполняются немедленно. Они лишь описывают преобразование и добавляются в конвейер.
- Возвращают Stream: Результатом всегда является новый объект
Stream, что позволяет строить цепочки вызовов. - Примеры:
filter(),map(),flatMap(),distinct(),sorted(),peek(),limit(),skip().
Терминальные операции (Terminal Operations):
- Энергичные (Eager): Запускают выполнение всего конвейера. Без терминальной операции поток не обработается.
- Завершают поток: Поток после вызова терминальной операции считается потребленным и не может быть использован повторно.
- Возвращают не-Stream: Результатом может быть значение (
reduce()), коллекция (collect()), примитив (count()) илиvoid(forEach()). - Примеры:
forEach(),collect(),reduce(),count(),anyMatch(),allMatch(),findFirst(),min(),max().
Пример потока с разбором операций:
List<String> result = names.stream() // Источник потока
.filter(name -> name.length() > 3) // Промежуточная: фильтрация
.map(String::toUpperCase) // Промежуточная: преобразование
.sorted() // Промежуточная: сортировка
.collect(Collectors.toList()); // Терминальная: сбор в список
// 1. Поток создан (stream())
// 2-4. Конвейер из промежуточных операций построен, но не выполнен.
// 5. Вызов collect() запускает весь конвейер: фильтрацию, маппинг, сортировку и сбор результата.
Важное правило: Поток можно обработать только одной терминальной операцией.