← Назад к вопросам

Приведи пример результирующих функций в Stream API

2.2 Middle🔥 163 комментариев
#Java

Комментарии (3)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Примеры терминальных (результирующих) операций в Stream API

Терминальные операции в Stream API (также называемые результирующими) — это операции, которые запускают обработку потока данных и возвращают конкретный результат (не Stream), завершая таким образом цепочку вызовов. После выполнения терминальной операции поток считается потреблённым и не может быть использован повторно. Вот ключевые примеры:

1. collect() – сбор элементов в коллекцию или агрегированный результат

Самый гибкий метод, часто используемый для преобразования потока в стандартные коллекции (List, Set, Map) или с помощью сложных коллекторов (Collectors).

// Сбор в List
List<String> names = Stream.of("Анна", "Иван", "Мария", "Пётр")
        .filter(name -> name.length() > 4)
        .collect(Collectors.toList()); // Результат: ["Анна", "Мария", "Пётр"]

// Сбор в Set (уникальные значения)
Set<Integer> numbers = Stream.of(1, 2, 2, 3, 4, 4)
        .collect(Collectors.toSet()); // Результат: [1, 2, 3, 4]

// Сбор в Map (ключ-значение)
Map<String, Integer> nameLengthMap = Stream.of("Анна", "Иван")
        .collect(Collectors.toMap(
            name -> name,          // keyMapper
            String::length         // valueMapper
        )); // Результат: {"Анна"=4, "Иван"=4}

// Группировка по критерию (очень мощный коллектор!)
Map<Integer, List<String>> groupedByLength = Stream.of("Аня", "Иван", "Ольга")
        .collect(Collectors.groupingBy(String::length));
// Результат: {3=["Аня"], 4=["Иван", "Ольга"]}

2. forEach() – выполнение действия для каждого элемента

Используется для побочных эффектов (например, логирование, запись в файл). Не рекомендуется для модификации внешних переменных в параллельных потоках.

// Простой вывод в консоль
Stream.of("Java", "Python", "C++")
        .forEach(System.out::println);

// Более сложное действие
List<String> resultList = new ArrayList<>();
Stream.of("data1", "data2", "data3")
        .forEach(resultList::add); // Добавление в внешнюю коллекцию

3. toArray() – преобразование в массив

Полезно при необходимости совместимости со старым кодом, работающим с массивами.

// Преобразование в массив Object[]
Object[] objects = Stream.of(1, 2, 3).toArray();

// Преобразование в типизированный массив с помощью функции-генератора
Integer[] integers = Stream.of(1, 2, 3)
        .toArray(Integer[]::new); // Результат: [1, 2, 3]

4. Методы агрегации: count(), min(), max(), sum(), average()

// count() – количество элементов
long count = Stream.of(1, 2, 3, 4, 5)
        .filter(n -> n % 2 == 0)
        .count(); // Результат: 2

// min()/max() – минимальный/максимальный элемент (требуют Comparator)
Optional<Integer> min = Stream.of(5, 2, 8, 1)
        .min(Integer::compareTo); // Результат: Optional[1]

// sum() и average() доступны для числовых потоков (IntStream, LongStream, DoubleStream)
double average = IntStream.of(10, 20, 30)
        .average() // Возвращает OptionalDouble
        .orElse(0.0); // Результат: 20.0

5. reduce() – свёртка потока к одному значению

Базовый метод для реализации собственной агрегации, аналогичный операции "fold" в функциональных языках.

// Сумма чисел
Optional<Integer> sum = Stream.of(1, 2, 3, 4)
        .reduce((a, b) -> a + b); // Результат: Optional[10]

// С начальным значением (identity)
Integer product = Stream.of(1, 2, 3, 4)
        .reduce(1, (a, b) -> a * b); // Результат: 24

// Более сложная свёртка: конкатенация строк с разделителем
String concatenated = Stream.of("a", "b", "c")
        .reduce("", (partial, element) -> 
            partial + (partial.isEmpty() ? "" : "-") + element
        ); // Результат: "a-b-c"

6. Методы поиска и проверки: findFirst(), findAny(), anyMatch(), allMatch(), noneMatch()

// Поиск первого элемента (важно для ordered streams)
Optional<String> first = Stream.of("a", "b", "c")
        .findFirst(); // Результат: Optional["a"]

// Проверка условий
boolean hasEven = Stream.of(1, 3, 5, 7, 8)
        .anyMatch(n -> n % 2 == 0); // Результат: true (есть хотя бы одно чётное)

boolean allPositive = Stream.of(1, 2, 3)
        .allMatch(n -> n > 0); // Результат: true (все положительные)

boolean noNegative = Stream.of(1, 2, 3)
        .noneMatch(n -> n < 0); // Результат: true (нет отрицательных)

7. Итераторы и сплитераторы

Для интеграции с legacy-кодом или ручной обработки.

// Получение итератора
Iterator<String> iterator = Stream.of("a", "b", "c").iterator();

// Получение сплитератора (для параллельной обработки)
Spliterator<String> spliterator = Stream.of("a", "b", "c").spliterator();

Ключевые особенности терминальных операций:

  • Ленивое выполнение – обработка начинается только при вызове терминальной операции
  • Потребление потока – после вызова терминальной операции поток нельзя повторно использовать
  • Оптимизация – многие операции (count(), min()/max() для отсортированных потоков) имеют оптимизации
  • Короткое замыкание – операции findFirst(), anyMatch() могут завершиться досрочно

Выбор конкретной терминальной операции зависит от задачи: нужна ли коллекция (collect()), агрегированное значение (reduce(), sum()), проверка условия (anyMatch()) или просто побочный эффект (forEach()). Для большинства сценариев преобразования данных collect() с использованием богатого набора Collectors является наиболее универсальным и выразительным инструментом.