Group and Aggregate Employees by Department with Streams
javaJavainterview-prepintermediatejava
Collectors.groupingBy with a downstream collector: names per department, average salary, the top earner of each department, and a partition into two groups.
import java.util.*;
import java.util.stream.*;
public class GroupByDepartment {
record Employee(String name, String department, double salary) { }
public static void main(String[] args) {
List<Employee> employees = List.of(
new Employee("Asha", "IT", 90000),
new Employee("Ben", "HR", 50000),
new Employee("Carla", "IT", 70000),
new Employee("Dev", "Finance", 65000),
new Employee("Esha", "HR", 55000));
// groupingBy(classifier, mapFactory, downstream): TreeMap keeps the departments sorted
Map<String, List<String>> namesByDepartment = employees.stream()
.collect(Collectors.groupingBy(Employee::department, TreeMap::new,
Collectors.mapping(Employee::name, Collectors.toList())));
System.out.println(namesByDepartment); // {Finance=[Dev], HR=[Ben, Esha], IT=[Asha, Carla]}
Map<String, Double> averageSalary = employees.stream()
.collect(Collectors.groupingBy(Employee::department, TreeMap::new,
Collectors.averagingDouble(Employee::salary)));
System.out.println(averageSalary); // {Finance=65000.0, HR=52500.0, IT=80000.0}
Map<String, String> topEarner = employees.stream()
.collect(Collectors.groupingBy(Employee::department, TreeMap::new,
Collectors.collectingAndThen(
Collectors.maxBy(Comparator.comparingDouble(Employee::salary)),
best -> best.get().name())));
System.out.println(topEarner); // {Finance=Dev, HR=Esha, IT=Asha}
// partitioningBy always returns both keys, false and true
Map<Boolean, Long> byPay = employees.stream()
.collect(Collectors.partitioningBy(e -> e.salary() >= 65000, Collectors.counting()));
System.out.println(byPay); // {false=2, true=3}
}
}