How do you group first and then apply filtering using Java streams?
Example: Consider this Employee
class:
I want to group by Department with a list of an employee having a salary greater than 2000.
public class Employee {
private String department;
private Integer salary;
private String name;
//getter and setter
public Employee(String department, Integer salary, String name) {
this.department = department;
this.salary = salary;
this.name = name;
}
}
This is how I can do this
List<Employee> list = new ArrayList<>();
list.add(new Employee("A", 5000, "A1"));
list.add(new Employee("B", 1000, "B1"));
list.add(new Employee("C", 6000, "C1"));
list.add(new Employee("C", 7000, "C2"));
Map<String, List<Employee>> collect = list.stream()
.filter(e -> e.getSalary() > 2000)
.collect(Collectors.groupingBy(Employee::getDepartment));
Output
{A=[Employee [department=A, salary=5000, name=A1]],
C=[Employee [department=C, salary=6000, name=C1], Employee [department=C, salary=7000, name=C2]]}
As there are no employees in Department B with a salary greater than 2000. So there is no key for Department B: But actually, I want to have that key with empty list –
Expected output
{A=[Employee [department=A, salary=5000, name=A1]],
B=[],
C=[Employee [department=C, salary=6000, name=C1], Employee [department=C, salary=7000, name=C2]]}
How can we do this?
You can make use of the Collectors.filtering
API introduced since Java-9 for this:
Map<String, List<Employee>> output = list.stream()
.collect(Collectors.groupingBy(Employee::getDepartment,
Collectors.filtering(e -> e.getSalary() > 2000, Collectors.toList())));
Important from the API note :
The filtering() collectors are most useful when used in a multi-level reduction, such as downstream of a
groupingBy
orpartitioningBy
.A filtering collector differs from a stream's
filter()
operation.