Java Predicate with Examples

In mathematics, a predicate is commonly understood as a boolean-valued function 'P:X ? {true, false}', called the predicate on X. Let’s learn how the Java Predicate interface helps write filter expressions easily.

1. When to use a Predicate

Introduced in Java 8, Predicate is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference.

So, where do you think, we can use these true/false returning functions in day-to-day programming? I will say we can use predicates anywhere we need to evaluate a condition on a collection of objects such that evaluation can result either in true or false.

For example, we can use predicates in these real-life usecases:

  • Find all children born after a particular date
  • Pizzas ordered within a specific time range
  • Employees older than a certain age
  • and so on…

2. Creating a Predicate

As mentioned earlier, predicates evaluate an expression and return a boolean value. Now let us see a few examples of creating simple predicates with a simple example.

Predicate<Employee> isAdult = e -> e.getAge() > 18;

Predicate<Employee> isMale = p -> p.getGender().equalsIgnoreCase("M");

We can create a complex Predicate by mixing two or more predicates.

Predicate<Employee> isAdultMale= isAdult.and(isMale);

Predicate<Employee> isAdultOrMale = isAdult.or(isMale);

It is possible to create a reverse predicate of an existing Predicate using the negate() method.

Predicate<Employee> isMinor = isAdult.negate();

3. Using Predicate with Streams

As we know, Predicate is a functional interface, meaning we can pass it in lambda expressions wherever a predicate is expected. For example, one such method is filter() method from Stream interface.

/**
 * Returns a stream consisting of the elements of this stream that match the given predicate.
 */
Stream<T> filter(Predicate<? super T> predicate);

So, essentially we can use stream and predicate to –

  • first filter certain elements from a group, and
  • then, perform some operations on filtered elements.

In the following example, we find all the male employees using the Predicate isMale and collect all male employees into a new List.

Predicate<Employee> isMale = p -> p.getGender().equalsIgnoreCase("M");

List<Employee> maleEmployeeList = employeeList.stream().filter(isMale).toList();

Note that if we want to use two arguments to test a condition, we can also use BiPredicate class.

BiPredicate<Integer, String> isAdultMale = (p1, p2) -> p1 > 18 && p2.equalsIgnoreCase("M");

List<Employee> adultMalesList = employeeList.stream()
  .filter(x -> isAdultMale.test(x.getAge(), x.getGender()))
  .toList();

4. Conclusion

  • Predicates move the conditions (sometimes business logic) to a central place. This helps in unit-testing them separately.
  • Any code change need not be duplicated into multiple places; thus, predicates improve code maintenance.
  • The names predicates such as “isAdultFemale()” are much more readable than writing a if-else block.

Happy Learning !!

Sourcecode on Github

Leave a Reply

9 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.

Our Blogs

REST API Tutorial