160. Java Lambda 表达式 - Predicate<T>的链式组合

89 阅读2分钟

160. Java Lambda 表达式 - Predicate的链式组合

在 Java 中,Predicate<T> 是一个非常实用的函数式接口,用于表示一个接收输入并返回布尔值的逻辑判断。它被广泛应用于过滤、条件判断等场景。

🎯 场景说明

假设我们有一个字符串列表,我们希望保留符合以下三个条件的字符串:

  1. null
  2. 非空(即长度不为 0);
  3. 长度小于 5 个字符。

我们可以很直接地使用一个 Predicate<String> 来实现这三个判断:

Predicate<String> p = s -> (s != null) && !s.isEmpty() && s.length() < 5;

虽然这种方式功能上没问题,但代码可读性稍差,尤其是在逻辑变复杂时。


🌟 更优雅的方式:将谓词拆分 + 链式组合

我们可以将每个判断逻辑拆分成独立的 Predicate,然后使用默认方法 .and() 进行组合:

Predicate<String> nonNull = s -> s != null;
Predicate<String> nonEmpty = s -> !s.isEmpty();
Predicate<String> shorterThan5 = s -> s.length() < 5;

Predicate<String> p = nonNull.and(nonEmpty).and(shorterThan5);

👉 这样做有什么好处?

  • 提高可读性:每个判断条件语义明确;
  • 便于单独复用:每个小谓词都可以独立用于其他场景;
  • 符合函数式编程原则:组合小函数构建复杂逻辑。

🔧 它是如何工作的?

这得益于 Predicate<T> 接口中的几个 默认方法(default methods):

方法描述
.and(Predicate)与(AND)逻辑组合
.or(Predicate)或(OR)逻辑组合
.negate()非(NOT)逻辑取反

这些方法是 默认方法(default methods),可以直接在 Predicate 实例上链式调用,不用我们自己写组合逻辑!


🧪 示例:使用方法引用 + 默认方法提升可读性

Predicate<String> isNull = Objects::isNull;
Predicate<String> isEmpty = String::isEmpty;

// 是 null 或 空
Predicate<String> isNullOrEmpty = isNull.or(isEmpty);

// 不是 null 且 非空
Predicate<String> isNotNullNorEmpty = isNullOrEmpty.negate();

// 小于 5 个字符
Predicate<String> shorterThan5 = s -> s.length() < 5;

// 最终组合
Predicate<String> p = isNotNullNorEmpty.and(shorterThan5);

解释:

  • Objects::isNull 是静态方法引用,用于判断是否为 null;
  • String::isEmpty 是未绑定实例方法引用;
  • or() 把两个谓词组合为“是 null 或空”;
  • negate() 表示非,即“不是 null 且非空”;
  • 最后通过 .and() 与长度判断组合形成完整判断逻辑。

💡 总结

通过使用 Predicate 接口的默认方法,我们可以:

  • 🌱 构建更具表现力的判断逻辑
  • 🧱 将复杂逻辑拆分为可复用的小模块
  • 链式组合,提高可维护性和可读性

🧠 小练习

试试实现一个判断数字是否是 正数且为偶数Predicate<Integer>,并用 .and().negate() 试试组合更多逻辑吧!

Predicate<Integer> isPositive = i -> i > 0;
Predicate<Integer> isEven = i -> i % 2 == 0;

Predicate<Integer> isPositiveAndEven = isPositive.and(isEven);