Java 8 Streams: когда использовать collect() или reduce()

Пройдите тест, узнайте какой профессии подходите

Я предпочитаю
0%
Работать самостоятельно и не зависеть от других
Работать в команде и рассчитывать на помощь коллег
Организовывать и контролировать процесс работы

Быстрый ответ

Если требуется собрать элементы потока в такие коллекции, как List, Set или Map, ваш выбор – collect. Вам помогут методы класса Collectors:

Java
Скопировать код
List<String> собраноВместе = поток.collect(Collectors.toList());

Это похоже на приручение дикого единорога.

А когда вам нужно преобразовать элементы потока в один итоговый результат, лучше использовать reduce. Он идеален для вычисления сумм, нахождения минимума или максимума, а также для конкатенации строк:

Java
Скопировать код
String объединенноеСоответствие = поток.reduce("", String::concat);

Такое сочетание напоминает смешивание идеального коктейля.

Кинга Идем в IT: пошаговый план для смены профессии

Лёгкое усвоение: Как использовать collect

Метод collect собирает элементы с помощью изменяемого контейнера, например, ArrayList или StringBuilder. Важны следующие моменты:

  1. Потокобезопасность: При параллельной обработке collect() обеспечивает безопасность, используя изолированные от потоков контейнеры.
  2. Специальные Накопители: Collectors предоставляет готовые решения для группирования, разделения данных и подведения итогов.
  3. Повышенная производительность со строками:
    С использованием StringBuilder и collect() вам не придется беспокоиться о расходе памяти и можно будет наслаждаться высокой скоростью обработки.
Java
Скопировать код
String бойкийРезультат = поток.collect(StringBuilder::new, StringBuilder::append, StringBuilder::append).toString();

Переворачиваем монету: Где использовать reduce

reduce подходит для работы с неизменяемыми объектами и для выполнения операций, требующих создания новых значений, например, в арифметических вычислениях.

  1. Немутабельное Сокращение: Например, точный расчёт с помощью BigDecimal.
  2. Последовательная Обработка: Если вам подходят последовательные потоки, выбирайте reduce.
  3. Бинарные Операции: Применяйте reduce, когда результат и элементы потока имеют один и тот же тип.
Java
Скопировать код
int сумма = поток.reduce(0, Integer::sum);

Так числа могут сосуществовать в гармонии.

Удваиваем ставки: Продвинутые приёмы и соображения

Здесь несколько советов для опытных разработчиков.

Создание Пользовательских Коллекторов

Если встроенных Collectors вам не хватает, создайте свой Collector для точного контроля над процессом:

Java
Скопировать код
Collector<Widget, ?, TreeSet<Widget>> вНабор =
    Collector.of(TreeSet::new, TreeSet::add,
                 (left, right) -> { left.addAll(right); return left; });

Сочетание Коллекторов: Высший уровень мастерства

Скомбинируйте Collectors, чтобы создать комплексные структуры данных:

Java
Скопировать код
Map<Integer, List<String>> группировкаПоДлине = 
    поток.collect(Collectors.groupingBy(String::length, Collectors.toList()));

Навигация по параллельным потокам с помощью reduce

Для эффективной параллельной обработки убедитесь, что ваш бинарный оператор ассоциативен и коммутативен. Это поможет избежать ошибок при параллельной обработке данных.

Соображения о производительности

Следует помнить, что при использовании reduce частое создание объектов может негативно сказаться на производительности.

Визуализация

ТехникаКухонный ИнструментРезультат Блюда
collect🍽 Поднос Для Подачи🌟 Изысканное Блюдо
reduce🔪 Поварской Нож💪 Концентрированный Вкус

collect идеально подходит для формирования сложных и изысканных коллекций:

Java
Скопировать код
поток().collect(Collectors.toList());

reduce позволяет комбинировать элементы в компактные и мощные структуры:

Java
Скопировать код
поток().reduce((a, b) -> a + b);

Параллельные потоки и их особенности

collect с Параллельными Потоками

Благодаря способности collect эффективно управлять конкуренцией, его можно использовать и с параллельными потоками. Однако иногда это может привести к небольшому ухудшению производительности.

Java
Скопировать код
List<String> параллельноСобрано = поток.parallel().collect(Collectors.toList());

reduce в Параллельной Вселенной

reduce может работать без синхронизации при выполнении простых задач, что благотворно влияет на производительность. Однако следует пристально контролировать работу бинарного оператора при использовании параллельных потоков.

Java
Скопировать код
int параллельнаяСумма = поток.parallel().reduce(0, Integer::sum);

Полезные материалы

  1. Collectors (Java Platform SE 8 ) — официальная документация Java, посвященная классу Collector.
  2. Stream (Java Platform SE 8 ) — документация Java, раскрывающая детали исполнения метода reduce.
  3. Java 8 Streams – collect vs reduce – Stack Overflow — обсуждение на Stack Overflow с примерами применения collect и reduce.
  4. Reduction (The Java™ Tutorials > Collections > Aggregate Operations) — учебное пособие Oracle, раскрывающее тему операций сокращения потоков в Java.