Java 8 - Filtering with Predicates

In this post, we will cover following items.

  • What is java.util.function.Predicate?
  • How to filter data with Predicates?
  • Predicate chaining.

Java 8 introduced many new features like Streaming API, Lambdas, Functional interfaces, default methods in interfaces and many more.

Today, we will discuss about Predicate interface added in java.util.function package and its usage in filtering in-memory data.

What is java.util.function.Predicate?

Predicate is like a condition checker, which accepts one argument of type T and return the boolean value.

It's a functional interface with functional method test(Object). Here, Object is typed.

@FunctionalInterface
interface Predicate<T> {
  public boolean test(T t);
}

How we can filter data with Predicates?

Consider we have Collection of employees and we want to filter them based on age, sex, salary and/ or with any other combinations. We can do that with Predicate.

Let's understand this with one short example.

class Employee {
  private long id;
  private String firstName;
  private String lastName;
  private int age;
  private Sex sex;
  private int salary;

  // getters, constructor, hashCode, equals, to String
}

Defining predicates for filtering

Predicate<Employee> male = e -> e.getSex() == Sex.MALE;
Predicate<Employee> female = e -> e.getSex() == Sex.FEMALE;
Predicate<Employee> ageLessThan30 = e -> e.getAge() < 30;
Predicate<Employee> salaryLessThan20 = e -> e.getSalary() < 20000;
Predicate<Employee> salaryGreaterThan25 = e -> e.getSalary() > 25000;

Filtering employees with Predicates

employees.stream().filter(male).collect(Collectors.toList());
employees.stream().filter(female).collect(Collectors.toList());
employees.stream().filter(ageLessThan30).collect(Collectors.toList());
employees.stream().filter(salaryLessThan20).collect(Collectors.toList());

Here, employees reference is of type java.util.List.

Collections framework is retrofitted for Streaming API and have stream() and parallelStream() methods along with few other additions.filter() method is defined in Stream. We are streaming employees collection and filtering them based on the Predicate and then collecting as java.util.List.

Predicate chaining

java.util.function.Predicate have three default method. Two of them and(Predicate<T> other) and or(Predicate<T> other) is used for predicate chaining.

Filtering employees with multiple predicates

Let's say, we want to filter collection of employees which involves multiple conditions like

  • all male salary less than 20k.
  • all female salary greater than 25k.
  • all male salary either less than 20 k or greater than 25k.

Let's understand this with quick example.

Defining predicates

Predicate<Employee> male = e -> e.getSex() == Sex.MALE;
Predicate<Employee> female = e -> e.getSex() == Sex.FEMALE;
Predicate<Employee> ageLessThan30 = e -> e.getAge() < 30;
Predicate<Employee> salaryLessThan20 = e -> e.getSalary() < 20000;
Predicate<Employee> salaryGreaterThan25 = e -> e.getSalary() > 25000;
Predicate<Employee> salaryLessThan20OrGreateThan25 = salaryLessThan20.or(salaryGreaterThan25);

Predicate<Employee> allMaleSalaryLessThan20 = male.and(salaryLessThan20);
Predicate<Employee> allMaleAgeLessThan30 = male.and(ageLessThan30);
Predicate<Employee> allFemaleSalaryGreaterThan25 = female.and(salaryGreaterThan25);

Predicate<Employee> allMaleSalaryLessThan20OrGreateThan25 = male.and(salaryLessThan20OrGreateThan25);

Line 1 => Predicate test for employee male

Line 2 => Predicate test for employee female

Line 3 => Predicate test for employee age less than 30

Line 4 => Pedicate test for employee salary less than 20000

Line 8 => Predicate test for employee male and salary less than 20000

Line 10 => Predicate test for employee female and salary greater than 25000

Line 12 => Predicate test for employee male and salary either less than 20000 or greater than 25000

Filtering employees with predicate chaining

employees.stream().filter(allMaleSalaryLessThan20).collect(Collectors.toList());
employees.stream().filter(allMaleAgeLessThan30).collect(Collectors.toList());
employees.stream().filter(allFemaleSalaryGreaterThan25).collect(Collectors.toList());
employees.stream().filter(allMaleSalaryLessThan20OrGreateThan25).collect(Collectors.toList());

This is how we can use Predicate to filter in-memory data. I hope you find this post informative and helpful. You can get the full example code on Github.

7 comments :

  1. Nicely put. Very concise and clear.

    Small typo to correct: In your "Predicate Chaining" section, the method reads "add" instead of "and".

    ReplyDelete
    Replies
    1. Thanks for your comment. I have corrected the typo.

      Delete
    2. Thank for very clear and short explenation. It's very helpful.

      Delete
  2. This comment has been removed by a blog administrator.

    ReplyDelete