Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Агрегации в обработке потоков и структурах данных
Агрегация — это процесс объединения множества элементов в один результат. В Java это один из ключевых паттернов Stream API и является примером функционального стиля программирования.
Встроенные операции агрегации в Stream API
count() — подсчёт элементов:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
long count = numbers.stream().count(); // 5
sum(), average(), min(), max() — числовые агрегации через IntStream:
int sum = numbers.stream()
.mapToInt(Integer::intValue)
.sum(); // 15
Optional<Integer> max = numbers.stream()
.max(Integer::compareTo);
collect() — универсальная агрегация с Collectors:
// Список -> Множество
Set<Integer> uniqueNumbers = numbers.stream()
.collect(Collectors.toSet());
// Список -> Строка
String result = Arrays.asList("Java", "Stream", "API")
.stream()
.collect(Collectors.joining(", ", "[" , "]")); // [Java, Stream, API]
Collectors — встроенные стратегии агрегации
toList(), toSet(), toCollection() — собрать в коллекцию:
List<String> names = users.stream()
.map(User::getName)
.collect(Collectors.toList());
toMap() — преобразование в ассоциативный массив:
Map<Integer, String> idToName = users.stream()
.collect(Collectors.toMap(User::getId, User::getName));
// С merge function для обработки дубликатов
Map<String, User> byEmail = users.stream()
.collect(Collectors.toMap(
User::getEmail,
Function.identity(),
(existing, replacement) -> existing // берём первого
));
groupingBy() — группировка элементов по ключу:
// Группировка пользователей по статусу
Map<UserStatus, List<User>> usersByStatus = users.stream()
.collect(Collectors.groupingBy(User::getStatus));
// Более сложная группировка с подсчётом
Map<String, Long> countByDepartment = users.stream()
.collect(Collectors.groupingBy(
User::getDepartment,
Collectors.counting()
));
partitioningBy() — разделение на две группы (true/false):
Map<Boolean, List<Integer>> evenOdd = numbers.stream()
.collect(Collectors.partitioningBy(n -> n % 2 == 0));
// {true=[2, 4], false=[1, 3, 5]}
summarizingInt/Long/Double() — получить статистику:
IntSummaryStatistics stats = numbers.stream()
.mapToInt(Integer::intValue)
.summaryStatistics();
System.out.println(stats.getCount()); // 5
System.out.println(stats.getSum()); // 15
System.out.println(stats.getAverage()); // 3.0
System.out.println(stats.getMax()); // 5
Кастомная агрегация с reduce()
reduce() — обобщённая операция объединения элементов:
// Сумма
Optional<Integer> sum = numbers.stream()
.reduce((a, b) -> a + b);
// С начальным значением
int sumWithIdentity = numbers.stream()
.reduce(0, (a, b) -> a + b); // 0 + 1 + 2 + 3 + 4 + 5
// Сложная агрегация: объединение объектов
class Summary {
int count = 0;
int sum = 0;
}
Summary result = numbers.stream()
.reduce(
new Summary(),
(summary, num) -> {
summary.count++;
summary.sum += num;
return summary;
},
(s1, s2) -> { // combiner для параллельных потоков
s1.count += s2.count;
s1.sum += s2.sum;
return s1;
}
);
Параллельные агрегации
parallelStream() — использование многоядерности:
long count = hugeList.parallelStream()
.filter(condition)
.count();
Внимание: для параллелизма важна идемпотентность и thread-safety функций:
// ❌ Опасно (shared mutable state)
List<Integer> result = new ArrayList<>();
hugeList.parallelStream()
.forEach(n -> result.add(n * 2)); // race condition!
// ✅ Безопасно (функциональный подход)
List<Integer> result = hugeList.parallelStream()
.map(n -> n * 2)
.collect(Collectors.toList());
Агрегация в базах данных (SQL)
В контексте JPA/Hibernate агрегирование часто происходит на уровне БД для производительности:
@Query("SELECT new map(u.department as dept, COUNT(u) as count) " +
"FROM User u GROUP BY u.department")
List<Map<String, Object>> countByDepartment();
// С Spring Data Specifications
Specification<Order> spec = (root, query, cb) -> {
query.groupBy(root.get("customerId"));
return cb.isNotNull(root.get("id"));
};
Практические примеры
Вычисление среднего дохода по категориям:
Map<String, Double> avgIncomeByCategory = orders.stream()
.collect(Collectors.groupingBy(
Order::getCategory,
Collectors.averagingDouble(Order::getPrice)
));
Поиск топ-3 самых дорогих товаров:
List<Product> topExpensive = products.stream()
.sorted(Comparator.comparingDouble(Product::getPrice).reversed())
.limit(3)
.collect(Collectors.toList());
Преобразование иерархии в плоский список с агрегацией:
List<String> allTags = articles.stream()
.flatMap(article -> article.getTags().stream())
.distinct()
.collect(Collectors.toList());
Агрегации — один из самых мощных инструментов для обработки данных в Java. Выбор правильного Collector или reduce() стратегии влияет как на читаемость кода, так и на производительность.