Java 8 Stream collect grouping
Данная статья написана командой Vertex Academy. Это одна из статей из нашего Учебника по Java 8. Надеемся, что данная статья Вам будет полезна. Приятного прочтения!
В этой статье мы рассмотрим группировку данных с помощью Stream-ов в Java.
1. Введение
Stream API - новый способ взаимодействия с данными, представляя их в виде конечного потока данных.
Один из методов Stream-ов, collect принимает лямбда-выражение известное как коллектор (Collector), которое собирает данные в необходимую структуру.
С ними мы сегодня и научимся работать.
2. Grouping by property
Создадим класс Human
1 2 3 4 5 6 |
class Human { private final String name, surname; private final int friendsAmount; // constructors, getters, etc are omitted } |
Сгруппируем людей по фамилии
До Java 8
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
public static void main(String[] args) { List<Human> humans = Arrays.asList( new Human("Ned", "Stark", 1), new Human("Robb", "Stark", 2), new Human("Arya", "Stark", 1), new Human("Aegon", "Targaryen", 6), new Human("Daenerys", "Targaryen", 4), new Human("Jaime", "Lannister", 1), new Human("Tyrion", "Lannister", 3)); Map<String, List<Human>> map = new HashMap<>(); for (Human human : humans) { String surname = human.getSurname(); if (!map.containsKey(surname)) { // если фамилии еще нет - создаем новый список List<Human> humanList = new ArrayList<>(); humanList.add(human); map.put(surname, humanList); } else { // если фамилия есть - добавляем представителя семьи =) List<Human> humanList = map.get(surname); humanList.add(human); } } System.out.println(map); } |
Вывод
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
{ Lannister=[ {name='Jaime', surname='Lannister', friendsAmount=1}, {name='Tyrion', surname='Lannister', friendsAmount=3} ], Targaryen=[ {name='Aegon', surname='Targaryen', friendsAmount=6}, {name='Daenerys', surname='Targaryen', friendsAmount=4} ], Stark=[ {name='Ned', surname='Stark', friendsAmount=1}, {name='Robb', surname='Stark', friendsAmount=2}, {name='Arya', surname='Stark', friendsAmount=1} ] } |
В Java 8 мы можем воспользоваться методом collect в сочетании с groupingBy из Stream API
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public static void main(String[] args) { List<Human> humans = Arrays.asList( new Human("Ned", "Stark", 1), new Human("Robb", "Stark", 2), new Human("Arya", "Stark", 1), new Human("Aegon", "Targaryen", 6), new Human("Daenerys", "Targaryen", 4), new Human("Jaime", "Lannister", 1), new Human("Tyrion", "Lannister", 3)); Map<String, List<Human>> map = humans.stream() .collect(Collectors.groupingBy(Human::getSurname)); System.out.println(map); } |
3. Grouping objects by property + count
Сгруппируем людей по фамилиям и посчитаем их количество.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public static void main(String[] args) { List<Human> humans = Arrays.asList( new Human("Ned", "Stark", 1), new Human("Robb", "Stark", 2), new Human("Arya", "Stark", 1), new Human("Aegon", "Targaryen", 6), new Human("Daenerys", "Targaryen", 4), new Human("Jaime", "Lannister", 1), new Human("Tyrion", "Lannister", 3)); Map<String, Long> map = humans.stream() .collect(Collectors.groupingBy(Human::getSurname, Collectors.counting())); System.out.println(map); //output {Lannister=2, Targaryen=2, Stark=3} } |
4. Grouping objects by property + sum
Сгруппируем людей по фамилиям и найдем количество друзей группы
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public static void main(String[] args) { List<Human> humans = Arrays.asList( new Human("Ned", "Stark", 1), new Human("Robb", "Stark", 2), new Human("Arya", "Stark", 1), new Human("Aegon", "Targaryen", 6), new Human("Daenerys", "Targaryen", 4), new Human("Jaime", "Lannister", 1), new Human("Tyrion", "Lannister", 3)); Map<String, Integer> map = humans.stream() .collect(Collectors.groupingBy(Human::getSurname, Collectors.summingInt(Human::getFriendsAmount))); System.out.println(map); //output {Lannister=4, Targaryen=10, Stark=4} } |
Collectors.summingInt принимает лямбда-выражение (по чему будет производиться суммирование)
5. Grouping + mapping
При группировке мы так же можем указать нужную коллекцию для значений, а так же сами значения.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public static void main(String[] args) { List<Human> humans = Arrays.asList( new Human("Ned", "Stark", 1), new Human("Robb", "Stark", 2), new Human("Arya", "Stark", 1), new Human("Aegon", "Targaryen", 6), new Human("Daenerys", "Targaryen", 4), new Human("Jaime", "Lannister", 1), new Human("Tyrion", "Lannister", 3)); Map<String, Set<String>> map = humans.stream() .collect(Collectors.groupingBy(Human::getSurname, //группируем по фамилии Collectors.mapping(Human::getName, Collectors.toSet()))); // собираем имена в Set System.out.println(map); } |
Вывод
1 2 3 4 5 |
{ Lannister=[Jaime, Tyrion], Targaryen=[Aegon, Daenerys], Stark=[Arya, Robb, Ned] } |
В Java 8 есть еще множество полезных нововведений, которые можно найти тут
Надеемся - наша статья была Вам полезна. Есть возможность записаться на наши курсы по Java в Киеве. Детальнее - у нас на сайте.