groupingBy
TL;DR
Collectors.groupingBy()is used within acollect()terminal operation to group elements of a stream into aMap.- It functions similarly to a
GROUP BYclause in SQL. - The resulting Map uses the classification property as the Key, and a List of matching objects as the Value.
Concept
If you have a list of Employee objects, and you want to group them by Department, doing this manually requires loops, if-else blocks, and manual Map instantiation.
groupingBy(Function) automates this. You provide a function that extracts the classification key (e.g., Employee::getDepartment). It returns a Map<String, List<Employee>> where the keys are the departments, and the values are lists of employees belonging to that department.
Examples
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
class Employee {
String name;
String department;
public Employee(String n, String d) { name = n; department = d; }
public String getDepartment() { return department; }
public String getName() { return name; }
@Override
public String toString() { return name; }
}
public class GroupingByExample {
public static void main(String[] args) {
List<Employee> employees = Arrays.asList(
new Employee("Alice", "HR"),
new Employee("Bob", "IT"),
new Employee("Charlie", "HR"),
new Employee("David", "IT")
);
// 1. Basic Grouping
Map<String, List<Employee>> byDept = employees.stream()
.collect(Collectors.groupingBy(Employee::getDepartment));
System.out.println(byDept);
// {HR=[Alice, Charlie], IT=[Bob, David]}
// 2. Grouping and Counting (Downstream Collector)
Map<String, Long> countByDept = employees.stream()
.collect(Collectors.groupingBy(
Employee::getDepartment,
Collectors.counting() // Downstream collector
));
System.out.println(countByDept);
// {HR=2, IT=2}
}
}
Interview Questions
Q: What is a “Downstream Collector” in groupingBy?
A: By default, groupingBy(classifier) collects the grouped elements into a List. If you want to change what happens to those grouped elements, you pass a second argument called a Downstream Collector. For example, Collectors.groupingBy(Employee::getDept, Collectors.counting()) will group them by department, but instead of returning a List of employees, it counts them and returns a Map<String, Long>.
Q: Can you group by multiple fields?
A: Yes. You can nest groupingBy collectors inside each other. If you want to group by Department, and then by Gender within that department, you would write:
Collectors.groupingBy(Employee::getDept, Collectors.groupingBy(Employee::getGender))
This would result in a Map<String, Map<String, List<Employee>>>.