1. Overview

In this short tutorial, we’ll see how to negate a Predicate method reference using Java 11.

We’ll start with the limitations encountered in order to achieve this before Java 11. Then we’ll see how the Predicate.not() method helps, as well.

2. Before Java 11

First, let’s see how we managed to negate a Predicate before Java 11.

To start with, let’s create a Person class with an age field and an isAdult() method:

public class Person {
    private static final int ADULT_AGE = 18;

    private int age;

    public Person(int age) {
        this.age = age;
    }

    public boolean isAdult() {
        return age >= ADULT_AGE;
    }
}

Now, let’s imagine we have a list of people:

List<Person> people = Arrays.asList(
  new Person(1),
  new Person(18),
  new Person(2)
);

And we want to retrieve all the adult ones. To achieve that in Java 8, we can:

people.stream()                      
  .filter(Person::isAdult)           
  .collect(Collectors.toList());

However, what if we want to retrieve the non-adult people instead? Then we have to negate the predicate:

people.stream()                       
  .filter(person -> !person.isAdult())
  .collect(Collectors.toList());

Unfortunately, we are forced to let go of the method reference, even though we find it easier to read. A possible workaround is to create an isNotAdult() method on the Person class and then use a reference to this method:

people.stream()                 
  .filter(Person::isNotAdult)   
  .collect(Collectors.toList());

But maybe we don’t want to add this method to our API, or maybe we just can’t because the class isn’t ours. That’s when Java 11 arrives with the Predicate.not() method, as we’ll see in the following section.

3. The Predicate.not() Method

The Predicate.not() static method has been added to Java 11 in order to negate an existing Predicate.

Let’s take our previous example and see what that means. Instead of using a lambda or creating a new method on the Person class, we can just use this new method:

people.stream()                          
  .filter(Predicate.not(Person::isAdult))
  .collect(Collectors.toList());

That way, we don’t have to modify our API and still can rely on the readability of method references.

We can make this even clearer with a static import:

people.stream()                  
  .filter(not(Person::isAdult))  
  .collect(Collectors.toList());

4. Conclusion

In this short article, we’ve seen how to leverage the Predicate*.not()* method in order to maintain usage of method references for predicates, even if they are negated.

As usual, the full code of the article can be found over on GitHub.