Какие промежуточные (lazy) операции вы знаете в Java Stream API?

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

Ответ

Промежуточные операции в Stream API возвращают новый поток и являются «ленивыми» — они выполняются только при вызове терминальной операции.

Основные промежуточные операции:

Операция Описание
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 элементов.

Пример использования:

List<String> names = Arrays.asList("Anna", "Bob", "Alice", "Bob", "Alex");

List<String> result = names.stream()
        .filter(name -> name.length() > 3) // Оставляет Anna, Alice, Alex
        .map(String::toUpperCase)          // Преобразует в ANNA, ALICE, ALEX
        .distinct()                        // Убирает дубликаты (если бы были)
        .sorted()                          // Сортирует: ALEX, ALICE, ANNA
        .collect(Collectors.toList());     // Терминальная операция

System.out.println(result); // [ALEX, ALICE, ANNA]