Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Группировка (Grouping) в Java Streams
Группировка — это операция потокового API Java, которая позволяет разделить элементы коллекции на группы по одному или нескольким критериям и собрать результат в виде Map'а, где ключи — это критерии группировки, а значения — коллекции элементов.
Синтаксис
import java.util.stream.Collectors;
Map<Key, List<Element>> grouped = elements.stream()
.collect(Collectors.groupingBy(element -> groupingKey));
Простой пример
public class Person {
private String name;
private String city;
private int age;
// конструктор, геттеры...
}
public static void main(String[] args) {
List<Person> people = Arrays.asList(
new Person("Иван", "Москва", 30),
new Person("Мария", "СПб", 25),
new Person("Петр", "Москва", 35),
new Person("Анна", "СПб", 28)
);
// Группировать людей по городу
Map<String, List<Person>> peopleByCity = people.stream()
.collect(Collectors.groupingBy(Person::getCity));
/* Результат:
{
"Москва": [Иван, Петр],
"СПб": [Мария, Анна]
}
*/
peopleByCity.forEach((city, persons) -> {
System.out.println(city + ": " + persons);
});
}
Вложенная группировка
Можно группировать по нескольким критериям одновременно:
Map<String, Map<Integer, List<Person>>> groupedByCityAndAge = people.stream()
.collect(Collectors.groupingBy(
Person::getCity,
Collectors.groupingBy(Person::getAge)
));
/* Результат:
{
"Москва": {
30: [Иван],
35: [Петр]
},
"СПб": {
25: [Мария],
28: [Анна]
}
}
*/
Группировка с подсчетом
Map<String, Long> countByCity = people.stream()
.collect(Collectors.groupingBy(
Person::getCity,
Collectors.counting()
));
/* Результат:
{
"Москва": 2,
"СПб": 2
}
*/
Группировка с суммированием
Map<String, Integer> totalAgeByCity = people.stream()
.collect(Collectors.groupingBy(
Person::getCity,
Collectors.summingInt(Person::getAge)
));
/* Результат:
{
"Москва": 65,
"СПб": 53
}
*/
Группировка с условием
Фильтрация перед группировкой:
Map<String, List<Person>> adultsOver25 = people.stream()
.filter(p -> p.getAge() > 25)
.collect(Collectors.groupingBy(Person::getCity));
Группировка с преобразованием значений
Map<String, List<String>> namesByCity = people.stream()
.collect(Collectors.groupingBy(
Person::getCity,
Collectors.mapping(Person::getName, Collectors.toList())
));
/* Результат:
{
"Москва": ["Иван", "Петр"],
"СПб": ["Мария", "Анна"]
}
*/
Практический пример: Анализ заказов
public class Order {
private int id;
private String customer;
private String status; // "delivered", "pending", "cancelled"
private double amount;
// конструктор, геттеры...
}
List<Order> orders = Arrays.asList(
new Order(1, "Иван", "delivered", 1000),
new Order(2, "Мария", "pending", 2000),
new Order(3, "Иван", "delivered", 1500),
new Order(4, "Петр", "cancelled", 500)
);
// Сумма заказов по статусу
Map<String, Double> amountByStatus = orders.stream()
.collect(Collectors.groupingBy(
Order::getStatus,
Collectors.summingDouble(Order::getAmount)
));
// Количество заказов по клиенту
Map<String, Long> countByCustomer = orders.stream()
.collect(Collectors.groupingBy(
Order::getCustomer,
Collectors.counting()
));
// Группировка по клиенту и статусу
Map<String, Map<String, List<Order>>> ordersByCustomerAndStatus = orders.stream()
.collect(Collectors.groupingBy(
Order::getCustomer,
Collectors.groupingBy(Order::getStatus)
));
Группировка в TreeMap (отсортированная)
Map<String, List<Person>> sortedByCity = people.stream()
.collect(Collectors.groupingBy(
Person::getCity,
TreeMap::new, // используем TreeMap вместо HashMap
Collectors.toList()
));
Группировка с partition (бинарное разделение)
Map<Boolean, List<Person>> adultsSplit = people.stream()
.collect(Collectors.partitioningBy(p -> p.getAge() >= 18));
/* Результат:
{
true: [Иван, Мария, Петр, Анна], // все взрослые
false: []
}
*/
Сложный пример: Аналитика
var stats = people.stream()
.collect(Collectors.groupingBy(
Person::getCity,
Collectors.collectingAndThen(
Collectors.toList(),
list -> new CityStats(
list.size(),
list.stream().mapToInt(Person::getAge).average().orElse(0)
)
)
));
record CityStats(int count, double avgAge) {}
Производительность
- groupingBy() создает HashMap по умолчанию — O(n) по времени
- Для больших данных можно использовать параллельные потоки
Map<String, List<Person>> grouped = people.parallelStream()
.collect(Collectors.groupingByConcurrent(Person::getCity));
Итого
Группировка (groupingBy) — мощный инструмент Stream API для разделения данных по критериям. Позволяет одновременно фильтровать, преобразовывать и агрегировать данные. Используется для аналитики, статистики, и логического структурирования коллекций.