Ответ
Stream API предоставляет два типа операций: промежуточные (возвращают новый Stream) и терминальные (завершают поток и возвращают результат).
Промежуточные операции:
filter(Predicate<T>)– отбирает элементы, удовлетворяющие условию.map(Function<T, R>)– преобразует каждый элемент.flatMap(Function<T, Stream<R>>)– преобразует элемент в поток и объединяет все потоки в один.distinct()– удаляет дубликаты (используетequals()).sorted()/sorted(Comparator<T>)– сортирует элементы.peek(Consumer<T>)– выполняет действие для каждого элемента (часто для отладки).limit(long n)– ограничивает поток первымиnэлементами.skip(long n)– пропускает первыеnэлементов.
Терминальные операции:
forEach(Consumer<T>)– выполняет действие для каждого элемента.collect(Collector<T, A, R>)– собирает элементы в коллекцию или другую структуру.reduce(BinaryOperator<T>)– выполняет свертку элементов (например, нахождение суммы).count()– возвращает количество элементов.min(Comparator<T>)/max(Comparator<T>)– находит минимальный/максимальный элемент.anyMatch(Predicate<T>)/allMatch()/noneMatch()– проверяют, удовлетворяет ли поток условию.findFirst()/findAny()– возвращают опциональный элемент потока.
Пример использования:
List<String> result = names.stream()
.filter(name -> name.length() > 3) // Промежуточная
.map(String::toUpperCase) // Промежуточная
.sorted() // Промежуточная
.collect(Collectors.toList()); // Терминальная
Почему это важно: Промежуточные операции «ленивы» – вычисления происходят только при вызове терминальной операции, что оптимизирует обработку данных.