Вопрос с собеседования · Java

Чем 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 у примитивных стримов

Подробно

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-накопление.

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

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

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

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

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

Разбор темы

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

Партнёр платформы

Разбор собеседования с sotto

После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.

Разбор собеседования