Advanced Collectors: groupingBy, partitioningBy & Downstreams
1Concept
`java.util.stream.Collectors` enables complex data aggregations: `groupingBy()` groups stream elements into a `Map<K, List<T>>` based on a classification function; `partitioningBy()` partitions elements into a `Map<Boolean, List<T>>`. Downstream collectors (`counting()`, `summingDouble()`, `mapping()`) aggregate grouped values.
2Architecture Diagram
Stream Elements ---> [ Collectors.groupingBy(Employee::getDepartment) ]
| |
v v
Key: "ENGINEERING" Key: "FINANCE"
List: [Alice, Bob] List: [Charlie]3Code Example
Core Java
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class AdvancedCollectorsDemo {
record Employee(String name, String department, double salary) {}
public static void main(String[] args) {
List<Employee> staff = List.of(
new Employee("Alice", "Engineering", 140000),
new Employee("Bob", "Engineering", 125000),
new Employee("Charlie", "Finance", 110000),
new Employee("Diana", "Finance", 130000)
);
// Group by Department and calculate average salary downstream
Map<String, Double> avgSalaryByDept = staff.stream()
.collect(Collectors.groupingBy(
Employee::department,
Collectors.averagingDouble(Employee::salary)
));
System.out.println("=== Average Salary by Department ===");
avgSalaryByDept.forEach((dept, avg) -> System.out.printf("%s: $%.2f%n", dept, avg));
}
}4Expected Output
=== Average Salary by Department === Engineering: $132500.00 Finance: $120000.00
5Key Takeaways
- ✓`partitioningBy` is optimized for binary boolean conditions.
- ✓Downstream collectors allow nesting multi-level aggregations in a single pass.
- ✓Use `Collectors.toUnmodifiableList()` to guarantee immutable output collections.