The Predicate interface

A Predicate represents a filter or condition. It takes an object as its input perameter and returns true or false depending on whether the object in question matches the condition or filter in question. The Java Predicate interface is one of the standard functional interfaces prodivded out of the box so that you can define lambda expressions that define a condition or filter.

To write a predicate as a lambda expression in Java, we generally write the object argument followed by the expression that returns true/false. For example, a predicate that filters strings on whether they are 10+ characters in length would look like this:

(str) -> str.length() >= 10

Predicates with the Stream.filter() method: how to filter a list or stream using a lambda expression

The most common use of a Predicate is with the Stream.filter() method. We can stream a list (or other collection) of objects and then filter them on a particular condition before collecting the results. For example, we can iterate through all strings in a list that are 10 or more characters in length as follows:

List<String> strings = ...

strings.stream()
  .filter((str) -> str.length() >= 10)

So to get a sublist of all of the "long" strings, we could write:

List<String> strings = ...

List<String> longStrings = strings.stream()
  .filter((str) -> str.length() >= 10)
  .collect(Collectors.toList());

Defining a method that takes a lambda expression as a filter or condition

As with any other of the standard Java functional interfaces, we are not forced to use Predicate only with the Stream class. The Predicate interface is equally useful when we want to write our own methods that will take a lambda expression as a filter or condition.

The Predicate interface provides a test() method. This will invoke the lambda expression that defines the filter or condition. For example, we could write a findCachedObjects() method which takes a lambda expression defining the specific objects we wish to retrieve from our cache:

public  List<T> findCachedObjects(Predicate<T> whichObjects) {
	List<T> ret = new ArrayList();
	for (T obj : allCachedObjects()) {
		if (whichObjects.test(obj)) {
			ret.add(obj);
		}
	}
	return ret;
}

Then, the findCachedObjects() method can be invoked as follows:

List<Customer> matchingCustomers =
  findCachedObjects(c -> c.getCustomerName().equals(searchName));

The pros and cons of stream.filter() with a lambda expression

As illustrated above, the filter() method makes it extremely simple to pass in a lambda exprssion as a Predicate (filter) to get a sublist of matching items. This alluring simplicity can also be its downfall in the hands of a lazy developer!


If you enjoy this Java programming article, please share with friends and colleagues. Follow the author on Twitter for the latest news and rants.

Editorial page content written by Neil Coffey. Copyright © Javamex UK 2021. All rights reserved.