Как одним коллектором получить «количество элементов в каждой группе»?
groupingBy(classifier, counting()) — downstream-коллектор counting сворачивает каждую группу в число (Long).
- Другие downstream: summingInt, averagingDouble, mapping, maxBy, toSet
- Вложенная группировка: groupingBy(a, groupingBy(b))
- partitioningBy — разбиение на две группы по условию
А ещё counting возвращает Long; нужен Integer — collectingAndThen или summingInt(e -> 1)
Подробно
Сила groupingBy во втором аргументе — downstream-коллекторе, который сворачивает каждую группу дальше: counting() (размер), mapping/summingInt/averagingInt (агрегаты), maxBy/minBy. Так одной строкой получают «сотрудников по отделам» (counting) или «среднюю зарплату по отделам» — вложенная свёртка вместо ручного цикла.
Пример
Map<Dept, Long> count = emps.stream()
.collect(groupingBy(Emp::dept, counting()));
Map<Dept, Double> avgSalary = emps.stream()
.collect(groupingBy(Emp::dept, averagingInt(Emp::salary)));Что хотят услышать
- groupingBy с counting.
- Идея downstream-коллекторов.
Частые ошибки
- Искать несуществующий size() в toMap.
- Считать, что groupingBy умеет только Map<K,List<V>>.
Проверьте себя
Один верный вариант. Подумайте, потом откройте ответ.
Показать варианты и ответ
- ✗toMap(classifier, list -> list.size())
- ✗partitioningBy(classifier, counting())
- ✓groupingBy(classifier, counting())
- ✗reduce(0, (a,b) -> a+1) по всему стриму
Что спросят дальше
- Какие ещё downstream-коллекторы есть?
- Чем partitioningBy отличается от groupingBy?
Разбор темы
- Collectors и свёртка
reduce против collect, базовые коллекторы и ловушка toMap, группировка и downstream-коллекторы, характеристики и параллельность.
Связанные вопросы
Разбор собеседования с sotto
После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.