«1. Обзор

В этом кратком руководстве мы увидим, как отменить ссылку на метод Predicate с помощью Java 11.

Мы начнем с ограничений, с которыми пришлось столкнуться, чтобы добиться этого до Java 11. Затем мы посмотрите, как помогает метод Predicate.not().

2. До Java 11

Во-первых, давайте посмотрим, как нам удавалось инвертировать предикат до Java 11.

Для начала создадим класс Person с полем age и методом isAdult(): ~ ~~

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;
    }
}

Теперь давайте представим, что у нас есть список людей:

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

И мы хотим получить всех взрослых. Чтобы добиться этого в Java 8, мы можем:

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

Однако что, если вместо этого мы хотим получить невзрослых людей? Затем мы должны инвертировать предикат:

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

К сожалению, мы вынуждены отказаться от ссылки на метод, хотя нам кажется, что ее легче читать. Возможный обходной путь — создать метод isNotAdult() в классе Person, а затем использовать ссылку на этот метод:

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

Но, возможно, мы не хотим добавлять этот метод в наш API, а может быть, мы просто можем не потому, что класс не наш. Именно тогда появляется Java 11 с методом Predicate.not(), как мы увидим в следующем разделе.

3. Метод Predicate.not()

Статический метод Predicate.not() был добавлен в Java 11 для отмены существующего Predicate.

Давайте возьмем наш предыдущий пример и посмотрим, что это значит. Вместо того, чтобы использовать лямбду или создавать новый метод в классе Person, мы можем просто использовать этот новый метод:

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

Таким образом, нам не нужно изменять наш API, и мы по-прежнему можем полагаться на удобочитаемость метода использованная литература.

Мы можем сделать это еще яснее с помощью статического импорта:

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

4. Заключение

В этой короткой статье мы увидели, как использовать метод Predicate.not() для поддержания использования ссылок на методы для предикатов, даже если они инвертированы.

Как обычно, полный код статьи можно найти на GitHub.