Ответ
Промежуточные операции в Stream API (lazy operations) преобразуют один поток в другой и могут быть объединены в цепочку. Основные из них:
| Операция | Сигнатура | Назначение |
|---|---|---|
filter |
Stream<T> filter(Predicate<? super T>) |
Фильтрует элементы по условию (predicate). |
map |
<R> Stream<R> map(Function<? super T, ? extends R>) |
Преобразует каждый элемент (1 к 1). |
flatMap |
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<R>>) |
Преобразует элемент в поток и "склеивает" все потоки в один (1 ко многим). |
distinct |
Stream<T> distinct() |
Удаляет дубликаты (использует equals()). |
sorted |
Stream<T> sorted() / sorted(Comparator) |
Сортирует элементы (естественным порядком или компаратором). |
peek |
Stream<T> peek(Consumer<? super T>) |
Выполняет действие для каждого элемента (часто для отладки), не изменяя элементы. |
limit |
Stream<T> limit(long maxSize) |
Ограничивает поток первыми N элементами. |
skip |
Stream<T> skip(long n) |
Пропускает первые N элементов. |
Практический пример:
List<String> names = Arrays.asList("John", "Alice", "Bob", "Anna", "Alex");
List<String> result = names.stream()
.filter(name -> name.length() > 3) // Оставляем имена длиннее 3 букв: [John, Alice, Anna, Alex]
.map(String::toUpperCase) // Преобразуем в верхний регистр: [JOHN, ALICE, ANNA, ALEX]
.sorted() // Сортируем: [ALEX, ALICE, ANNA, JOHN]
.distinct() // Здесь дубликатов нет, но операция актуальна
.collect(Collectors.toList()); // Терминальная операция — собираем в список
System.out.println(result); // Вывод: [ALEX, ALICE, ANNA, JOHN]
Все эти операции являются "ленивыми" — вычисления происходят только после вызова терминальной операции (например, collect, forEach).