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
andfalse
– 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 -> String.valueOf(e.getId()))
.collect(Collectors.joining(",", "[", "]"));
System.out.println("Active employees = " + result);
//Active employees with active accounts
result = employeeList.stream()
.filter(isEmployeeActive.and(isAccountActive))
.map(e -> String.valueOf(e.getId()))
.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 -> String.valueOf(e.getId()))
.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 -> String.valueOf(e.getId()))
.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 !!
Comments