Получить доступ

Чем collect отличается от reduce при сборке стрима?

MiddleЛямбды и Stream API
Ещё спрашивают так:
  • Чем collect отличается от reduce и какие ловушки есть у Collectors.toMap и groupingBy?
Коротко

reduce — неизменяемая свёртка: из двух значений получается новое (сумма, максимум). collect — изменяемая свёртка: элементы накапливаются в один контейнер (список, карта, StringBuilder) через Collector. Коллекции и строки собирают только collect — reduce создавал бы новый объект на каждом шаге.

  • Ловушки toMap: дубликат ключа — IllegalStateException, null-значение — NPE
  • groupingBy по умолчанию HashMap и List; downstream-коллектор меняет агрегат
  • Для parallel: reduce требует ассоциативной функции и нейтрального элемента

А ещё Простые агрегаты: sum, count, max у примитивных стримов

Так подсказку видит пользователь sotto на живом собеседовании — за пару секунд, пока вы думаете вслух.

Подробно

reduce:

int total = orders.stream().map(Order::sum).reduce(0, Integer::sum);

identity — нейтральный элемент, функция — ассоциативная. Подходит для значений. Собирать так строку или список — на каждом шаге новый объект, сложность квадратичная.

collect:

Map<Dept, List<Emp>> byDept = emps.stream()
    .collect(Collectors.groupingBy(Emp::dept));
String csv = names.stream().collect(Collectors.joining(","));

Collector описывает поставщика контейнера, функцию добавления элемента и функцию слияния контейнеров (для parallel).

Ловушки Collectors:

  • toMap без функции слияния падает на дубликате ключа (IllegalStateException: Duplicate key);
  • toMap падает на null-значении (NPE) — внутри используется HashMap.merge;
  • groupingBy кладёт в HashMap — порядок групп не определён; нужен порядок — groupingBy(f, TreeMap::new, toList());
  • toList() у Stream (Java 16) неизменяемый, Collectors.toList() — изменяемый ArrayList без гарантии.

Что хотят услышать

  • Неизменяемая и изменяемая свёртка.
  • Почему коллекции собирают collect.
  • Ловушки toMap и groupingBy.

Частые ошибки

  • Собирать список через reduce с пересозданием контейнера.
  • Думать, что reduce умеет mutable-накопление.

Проверьте себя

Один верный вариант. Подумайте, потом откройте ответ.

Показать варианты и ответ
  • ✓reduce — неизменяемая свёртка (identity + ассоциативная функция), хороша для значений; collect — изменяемая свёртка в один мутируемый контейнер, для построения коллекций
  • ✗Они идентичны; collect — устаревший псевдоним reduce
  • ✗collect работает только последовательно, reduce — только параллельно
  • ✗reduce собирает в коллекцию, collect — в одно значение

Что спросят дальше

  • Что такое identity в reduce?
  • Зачем коллектору ассоциативность для параллели?
  • Что означают характеристики коллектора UNORDERED и CONCURRENT?
  • Когда параллельный стрим действительно даёт выигрыш?

Разбор темы

Связанные вопросы

Закрытая бета

Подсказки на собеседовании — в реальном времени

sotto слышит вопрос интервьюера и показывает короткий ответ и план, как в блоке «Коротко». Оставьте контакт — пришлём доступ и промокод.

  • Промокод на 2 часа — сверх пробных 30 минут
  • Программа для Windows — скачать сразу, войти — через Яндекс ID или VK ID
  • Прямая связь с разработчиком: что улучшить — сделаем