Core Java

Filter Nested Collections with Stream in Java

The Java Stream API offers powerful filtering capabilities for elements within a Stream. However, when these stream elements include nested collections, we may need to filter the elements within those nested collections as well. Let us delve into understanding how to filter nested collections using the Stream API.

1. Filter Nested Collections with Stream in Java

In Java, working with nested collections can sometimes be challenging, especially when you need to filter data based on certain conditions. The Stream API, introduced in Java 8, provides a powerful way to process collections in a declarative manner.

1.1 Understanding Nested Collections

A nested collection is a collection that contains other collections. For instance, a list of lists, a list of maps, or a map of lists are all examples of nested collections. To effectively filter nested collections, we often need to flatten them first.

1.2 Example Scenario

Let’s consider a scenario where we have a list of Department objects, and each Department contains a list of Employee objects. We want to filter out all employees who have a salary greater than a certain threshold.

import java.util.List;

class Employee {
    private String name;
    private double salary;

    public Employee(String name, double salary) {
        this.name = name;
        this.salary = salary;
    }

    public String getName() {
        return name;
    }

    public double getSalary() {
        return salary;
    }

    @Override
    public String toString() {
        return "Employee{name='" + name + "', salary=" + salary + "}";
    }
}

class Department {
    private String name;
    private List<Employee> employees;

    public Department(String name, List<Employee> employees) {
        this.name = name;
        this.employees = employees;
    }

    public String getName() {
        return name;
    }

    public List<Employee> getEmployees() {
        return employees;
    }
}

1.2.1 Filter employees using flatMap() and filter()

To filter the employees with a salary greater than a specified threshold, we will use the Stream API. Here’s how you can do it:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class FilterNestedCollections {
    public static void main(String[] args) {
        List<Employee> empList1 = Arrays.asList(
            new Employee("John Doe", 60000),
            new Employee("Jane Smith", 75000)
        );
        List<Employee> empList2 = Arrays.asList(
            new Employee("Jack White", 50000),
            new Employee("Jill Green", 90000)
        );
        
        List<Department> departments = Arrays.asList(
            new Department("HR", empList1),
            new Department("IT", empList2)
        );
        
        double salaryThreshold = 65000;
        
        List<Employee> filteredEmployees = departments.stream()
            .flatMap(department -> department.getEmployees().stream())
            .filter(employee -> employee.getSalary() > salaryThreshold)
            .collect(Collectors.toList());
        
        filteredEmployees.forEach(System.out::println);
    }
}

Here’s a code breakdown:

  • flatMap: This method is used to flatten the nested collections. In this case, we flatten the list of employees from each department into a single stream of employees.
  • filter: This method is used to filter the employees based on the salary condition.
  • collect: This method collects the filtered employees into a list.

The code output is:

Employee{name='Jane Smith', salary=75000.0}
Employee{name='Jill Green', salary=90000.0}

1.2.2 Filter employees using mapMulti()

With the addition of mapMulti in Java 16, filtering and flattening nested collections has become even more streamlined. Here’s how you can do it:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class FilterNestedCollections {
    public static void main(String[] args) {
        List<Employee> empList1 = Arrays.asList(
            new Employee("John Doe", 60000),
            new Employee("Jane Smith", 75000)
        );
        List<Employee> empList2 = Arrays.asList(
            new Employee("Jack White", 50000),
            new Employee("Jill Green", 90000)
        );
        
        List<Department> departments = Arrays.asList(
            new Department("HR", empList1),
            new Department("IT", empList2)
        );
        
        double salaryThreshold = 65000;
        
        List<Employee> filteredEmployees = departments.stream()
            .mapMulti((department, downstream) -> 
                department.getEmployees().stream()
                    .filter(employee -> employee.getSalary() > salaryThreshold)
                    .forEach(downstream::accept))
            .collect(Collectors.toList());
        
        filteredEmployees.forEach(System.out::println);
    }
}

Here’s a code breakdown:

  • mapMulti: This method is used to transform and flatten the stream in a single step. It takes a BiConsumer that accepts each element from the original stream and a downstream consumer to which the transformed elements are passed.
  • filter: This method is used within the mapMulti method to filter the employees based on the salary condition.
  • collect: This method collects the filtered employees into a list.

The code output is:

Employee{name='Jane Smith', salary=75000.0}
Employee{name='Jill Green', salary=90000.0}

2. Conclusion

The Stream API in Java provides a convenient and powerful way to process and filter nested collections. By using methods like flatMap and filter, you can easily handle complex data structures and extract the necessary information with minimal effort.

Yatin Batra

An experience full-stack engineer well versed with Core Java, Spring/Springboot, MVC, Security, AOP, Frontend (Angular & React), and cloud technologies (such as AWS, GCP, Jenkins, Docker, K8).
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button