Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Как сгруппировать список по полю

Короткий ответ

Collectors.groupingBy() собирает элементы в Map, где ключ — значение поля, а значение — список элементов:

record Employee(String name, String department) {}
 
void main() {
    var staff = List.of(
            new Employee("Anna", "IT"),
            new Employee("Oleg", "Sales"),
            new Employee("Boris", "IT"));
 
    Map<String, List<Employee>> byDepartment = staff.stream()
            .collect(Collectors.groupingBy(Employee::department));
    IO.println(byDepartment.get("IT"));
}

Результат:

[Employee[name=Anna, department=IT], Employee[name=Boris, department=IT]]

Сортированные ключи

По умолчанию результат — HashMap без порядка. Передайте TreeMap::new, чтобы ключи шли по алфавиту:

void main() {
    var words = List.of("apple", "bob", "avocado", "cat", "banana");
 
    var byLetter = words.stream()
            .collect(Collectors.groupingBy(w -> w.charAt(0), TreeMap::new, Collectors.toList()));
    IO.println(byLetter);
}

Результат:

{a=[apple, avocado], b=[bob, banana], c=[cat]}

Только нужное поле

mapping() превращает элементы группы перед сбором:

record Employee(String name, String department) {}
 
void main() {
    var staff = List.of(new Employee("Anna", "IT"), new Employee("Oleg", "Sales"), new Employee("Boris", "IT"));
 
    var names = staff.stream().collect(Collectors.groupingBy(Employee::department, TreeMap::new,
            Collectors.mapping(Employee::name, Collectors.toList())));
    IO.println(names);
}

Результат:

{IT=[Anna, Boris], Sales=[Oleg]}

Подсчёт в группах

counting() вместо списка даёт количество элементов:

void main() {
    var words = List.of("one", "two", "three", "four", "five", "six");
 
    var byLength = words.stream()
            .collect(Collectors.groupingBy(String::length, TreeMap::new, Collectors.counting()));
    IO.println(byLength);
}

Результат:

{3=3, 4=2, 5=1}

Частая ошибка

Группировать по полю, которое может быть null. groupingBy() не принимает null в качестве ключа:

record Employee(String name, String department) {}
 
void main() {
    var staff = List.of(new Employee("Anna", "IT"), new Employee("Ivan", null));
    staff.stream().collect(Collectors.groupingBy(Employee::department));
}

Результат:

Exception in thread "main" java.lang.NullPointerException: element cannot be mapped to a null key

Подставьте значение по умолчанию: e -> Objects.requireNonNullElse(e.department(), "none").

Функции из этого ответа

  • Collectors.groupingBy() — Сборщик, который раскладывает элементы по группам с общим ключом.
  • Collectors.counting() — Сборщик-счётчик; обычно используется внутри `groupingBy()`.
  • Collectors.partitioningBy() — Делит элементы потока на две группы по условию.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.