Applying Multiple Conditions on Java Streams

Learn to filter the items of a stream using multiple conditions similar to nested if-else conditions with for-loop. Also, learn to process the filtered items by either collecting to a new List or calling a method on each item matching the provided filter conditions.

1. Creating Predicates using Lambda Expressions

In Java streams API, a filter is a Predicate instance (boolean-valued function). It can be thought of as an operator or function that returns a value that is either true or false.

I will recommend to create one predicate per filter condition always and giving it a meaningful name. Later, we can combine multiple such simple filters to create a complex predicate representing multiple conditions that we need to apply.

  • Use negate() to write the reverse/negative conditions so that a single predicate may serve true and false – both scenarios.
  • Use and() to combine two predicates for a logical AND operation.
  • Use or() to combine two predicates for a logical OR operation.
Predicate<Integer> isEven = i -> i%2 == 0;
Predicate<Integer> isOdd = i -> i%2 == 1;

//Or use negate() to reverse the condition
Predicate<Integer> isOdd = isEven.negate();  
 
Predicate<Employee> isAdult = e -> e.getAge() > 18;
Predicate<Account> isActive = a -> a.getStatus() == AccountStatus.ACTIVE;

Predicate<Employee> isAdultAndActive = isAdult.and(isActive);
Predicate<Employee> isAdultOrActive = isAdult.or(isActive);
Predicate<Employee> isAdultAndInactive = isAdult.and(isActive.negate());

Similarly, we can create as many simple and complex predicates as we require.

2. Using Predicates for Multiple Conditions

After creating simple and complex predicates, we can use them with Stream.filter() method.

The given below is a Java program to filter an employees list with multiple different conditions using predicates.

import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
 
public class Main 
{
    public static void main(String[] args) 
    {
        List<Employee> employeeList = getEmployeesFromDataSource();
         
        //filter 1
        Predicate<Employee> isEmployeeActive = e -> e.getStatus() == EmployeeStatus.ACTIVE;
 
        //filter2
        Predicate<Employee> isAccountActive = e -> e.getAccount().getStatus() == AccountStatus.ACTIVE;
         
        //Active employees
        String result = employeeList.stream()
                .filter(isEmployeeActive)
                .map(e -> e.getId().toString())
                .collect(Collectors.joining(",", "[", "]"));
         
        System.out.println("Active employees = " + result);
         
        //Active employees with active accounts
        result = employeeList.stream()
                .filter(isEmployeeActive.and(isAccountActive))
                .map(e -> e.getId().toString())
                .collect(Collectors.joining(",", "[", "]"));
         
        System.out.println("Active employees with active accounts = " + result);
         
        //Active employees with inactive accounts
        result = employeeList.stream()
                .filter(isEmployeeActive.and(isAccountActive.negate()))
                .map(e -> e.getId().toString())
                .collect(Collectors.joining(",", "[", "]"));
         
        System.out.println("Active employees with inactive accounts = " + result);
         
        //Inactive employees with inactive accounts
        result = employeeList.stream()
                .filter(isEmployeeActive.negate().and(isAccountActive.negate()))
                .map(e -> e.getId().toString())
                .collect(Collectors.joining(",", "[", "]"));
         
        System.out.println("Inactive employees with inactive accounts = " + result);
    }
     
    private static List<Employee> getEmployeesFromDataSource() {
        List<Employee> employeeList = new ArrayList<>();
         
        employeeList.add(new Employee(1L, "A", "AA", EmployeeStatus.ACTIVE, 
            new Account(1001L, "Saving - 1001", "Saving", AccountStatus.ACTIVE)));
        employeeList.add(new Employee(2L, "B", "BB", EmployeeStatus.ACTIVE, 
            new Account(1002L, "Checking - 1002", "Checking", AccountStatus.ACTIVE)));
        employeeList.add(new Employee(3L, "C", "CC", EmployeeStatus.ACTIVE, 
            new Account(1003L, "Deposit - 1003", "Deposit", AccountStatus.ACTIVE)));
        employeeList.add(new Employee(4L, "D", "DD", EmployeeStatus.ACTIVE, 
            new Account(1004L, "Saving - 1004", "Saving", AccountStatus.INACTIVE)));
        employeeList.add(new Employee(5L, "E", "EE", EmployeeStatus.ACTIVE, 
            new Account(1005L, "Checking - 1005", "Checking", AccountStatus.INACTIVE)));
        employeeList.add(new Employee(6L, "F", "FF", EmployeeStatus.ACTIVE, 
            new Account(1006L, "Deposit - 1006", "Deposit", AccountStatus.BLOCKED)));
         
        return employeeList;
    }
}

Program output.

Active employees = [1,2,3,4,5,6]
Active employees with active accounts = [1,2,3]
Active employees with inactive accounts = [4,5,6]
Inactive employees with inactive accounts = []

Clearly, we can create many more such simple predicates, and then we can combine them to make more complex conditions. These complex predicates can help in filtering the streams and getting the desired output.

Happy Learning !!

Sourcecode on Github

Was this post helpful?

Join 7000+ Awesome Developers

Get the latest updates from industry, awesome resources, blog updates and much more.

* We do not spam !!

3 thoughts on “Applying Multiple Conditions on Java Streams”

Leave a Comment

HowToDoInJava

A blog about Java and related technologies, the best practices, algorithms, and interview questions.