Collectors.groupingBy
— это метод, который используется для группировки элементов потока (Stream) на основе заданного критерия. Он позволяет создать Map
, где ключом будет выступать значение, возвращаемое функцией группировки, а значением — коллекция элементов, которые соответствуют этому ключу. Рассмотрим принцип работы Collectors.groupingBy
и его различные варианты.
Общий алгоритм работы Collectors.groupingBy
- Создание потока данных:
Collectors.groupingBy
применяется к потоку (Stream) элементов. - Определение функции группировки: Сначала вы указываете функцию, которая будет определять ключи для группировки элементов.
- Указание коллектора для значений (необязательно): Дополнительно можно указать, как собирать значения для каждого ключа — это может быть, например,
Collectors.toList()
для списка илиCollectors.counting()
для подсчета количества элементов. - Выбор типа карты (необязательно): По умолчанию используется
HashMap
, но можно указать другой тип карты, например,TreeMap
, если нужен порядок по ключам.
Варианты использования Collectors.groupingBy
- Базовая группировка (по умолчанию —
HashMap
) В этом случаеgroupingBy
создает карту, где каждый ключ — это результат функции группировки, а значение — список элементов, соответствующих этому ключу.Map<String, List<Programmer>> map = programmers.stream() .collect(Collectors.groupingBy(Programmer::getName));
Алгоритм:- Для каждого программиста
getName
возвращает имя, которое используется как ключ. - Все программисты с одинаковым именем собираются в один список, который и становится значением для этого ключа.
- Для каждого программиста
- Группировка с модификацией значений (например,
Collectors.counting()
) Можно подсчитать количество элементов в каждой группе. ВместоList<Programmer>
в значении карты будетLong
, представляющий количество элементов.Map<String, Long> map = programmers.stream() .collect(Collectors.groupingBy(Programmer::getName, Collectors.counting()));
Алгоритм:getName
по-прежнему возвращает ключ (имя программиста).- Вместо списка значений используется
Collectors.counting()
, который подсчитывает количество элементов в каждой группе и возвращаетLong
.
- Группировка с указанием типа карты По умолчанию используется
HashMap
, но можно указать другой тип карты, например,TreeMap
илиLinkedHashMap
.Map<String, List<Programmer>> map = programmers.stream() .collect(Collectors.groupingBy(Programmer::getName, TreeMap::new, Collectors.toList()));
Алгоритм:getName
возвращает имя, используемое в качестве ключа.TreeMap::new
указывает, что карта должна бытьTreeMap
, что сортирует её по ключам.Collectors.toList()
собирает элементы каждой группы в список.
- Группировка по вычисленному ключу Допустим, вы хотите сгруппировать программистов по количеству технологий, которыми они владеют. В этом случае ключом будет количество технологий, а значением — список программистов с этим количеством.
Map<Integer, List<Programmer>> map = programmers.stream() .collect(Collectors.groupingBy(programmer -> programmer.getTechnologies().size()));
Алгоритм:- Ключ — это результат
programmer.getTechnologies().size()
(количество технологий у программиста). - Программисты с одинаковым количеством технологий собираются в списки.
- Ключ — это результат
- Многоуровневая группировка Можно вложить несколько
groupingBy
для создания вложенной карты. Например, сгруппируем программистов по количеству технологий, а затем внутри каждой группы — по имени.Map<Integer, Map<String, List<Programmer>>> map = programmers.stream() .collect(Collectors.groupingBy( programmer -> programmer.getTechnologies().size(), // Внешний ключ — количество технологий Collectors.groupingBy(Programmer::getName) // Внутренний ключ — имя ));
Алгоритм:- Сначала группируем программистов по количеству технологий.
- Внутри каждой такой группы применяем еще одну группировку по имени.
Резюме
Collectors.groupingBy
позволяет легко группировать элементы потока по определенному критерию.- Ключи карты определяются функцией группировки.
- Значения можно модифицировать, применяя другие коллекторы, например,
Collectors.counting()
,Collectors.toSet()
и т.д. - При необходимости можно указать тип карты или использовать многоуровневую группировку.
Надеюсь, этот алгоритм поможет вам эффективно использовать Collectors.groupingBy
для разных задач!