1. Overview

在本篇短文中,我们将学习如何在 Java 11 中优雅地对一个 Predicate 方法引用进行取反操作

我们会先回顾在 Java 11 之前我们是如何处理这类问题的,以及当时的局限性。然后,我们会介绍 Java 11 引入的 Predicate.not() 方法,并通过实际代码演示其用法。

  1. Java 11 之前的做法

在 Java 11 之前,如果我们想对一个 Predicate 进行取反,通常只能使用 lambda 表达式显式写出取反逻辑。

举个例子,我们先定义一个 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());

✅ 使用 Person::isAdult 方法引用,代码简洁清晰。

❌ 但如果我们想筛选出非成年人,Java 8 中只能这样写:

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

这时候就不能使用方法引用了,必须写成 lambda 表达式,牺牲了代码的简洁性。

一种变通方式是添加 isNotAdult() 方法:

public boolean isNotAdult() {
    return !isAdult();
}

然后这样使用:

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

⚠️ 但有时候我们不希望暴露这个方法到 API 中,或者我们根本无法修改原始类(比如它来自第三方库),这就显得有些笨拙了。

  1. Java 11 中的 Predicate.not() 方法

Java 11 引入了 Predicate.not() 方法,允许我们对一个 Predicate 进行取反,同时保持方法引用的可读性

继续使用上面的例子,我们现在可以这样写:

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

✅ 这样既保留了方法引用的语义清晰,又实现了逻辑取反。

我们还可以通过静态导入进一步简化代码:

import static java.util.function.Predicate.not;

// ...

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

⚠️ 注意:使用静态导入时要注意命名冲突,避免影响代码可读性。

  1. 总结

  • Java 11 引入的 Predicate.not() 方法让我们可以在不使用 lambda 表达式的情况下对谓词进行取反
  • 它保留了方法引用带来的可读性和简洁性。
  • 适用于需要对已有 Predicate 方法进行取反操作,但又不想修改类结构或牺牲代码风格的场景。

完整代码示例可参考:GitHub 项目地址


原始标题:Negate a Predicate Method Reference with Java 11