
用 Predicate 做集合过滤,别直接写 for 循环
Java 8+ 里,Predicate 是最轻量、最自然的自定义过滤方式。它本质就是一个接收对象、返回 boolean 的函数式接口,和 filter() 方法天然是配对的。硬写循环不仅啰嗦,还容易漏掉空指针或状态污染。
常见错误现象:NullPointerException 在 stream().filter(...) 中突然抛出,往往是因为 Predicate 内部没处理 null 入参;或者把带副作用的逻辑(比如修改原对象)塞进 Predicate.test(),结果行为不可预测。
- 过滤前先确认集合非空,但
Predicate本身**不负责判空入参**,得自己加Objects.nonNull()或三元判断 - 避免在
test()里做 I/O、改字段、发请求——Predicate应该是纯函数 - 如果要复用,优先定义成静态常量,比如
public static final Predicate<string> NOT_EMPTY = s -> s != null && !s.trim().isEmpty();</string>
filter() 链式调用时,Predicate 组合比嵌套 if 更安全
多个条件叠加时,新手常写成 list.stream().filter(x -> cond1(x) && cond2(x) && cond3(x))。这看似简单,但可读性差、复用难,且一旦某个条件抛异常,堆栈定位困难。
用 Predicate.and()、or()、negate() 组合,语义清晰,也方便单元测试拆解。
立即学习“Java免费学习笔记(深入)”;
-
Predicate<user> isAdult = u -> u.getAge() >= 18;</user>+Predicate<user> isActive = u -> Boolean.TRUE.equals(u.getActive());</user> - 组合:
isAdult.and(isActive),等价于u -> isAdult.test(u) && isActive.test(u),但中间步骤可单独验证 - 注意:
and()和or()是短路求值,和&&/||行为一致;但null的Predicate调用and()会 NPE,需提前判空
Stream 并行流下,Predicate 必须无状态
一旦用了 parallelStream(),Predicate 如果引用了外部可变变量(比如一个 AtomicInteger counter),结果就不可靠——不同线程可能看到不同值,甚至导致过滤漏项。
性能影响明显:有状态的 Predicate 在并行流中不仅错,还会因锁竞争拖慢速度,有时比串行还慢。
- 禁止在
Predicate里读写实例字段、静态变量、闭包中的非 final 变量 - 允许使用
final局部变量、常量、纯计算逻辑(如字符串长度判断、数值比较) - 若真需要上下文(比如“前一个元素是否满足”),说明这不是过滤,而是归约(
reduce())或遍历(forEach())场景
和 Guava 的 Predicates 或 Apache Commons Predicate 混用会出问题
老项目里可能还在用 Guava 的 com.google.common.base.Predicate,它和 Java 8 的 java.util.function.Predicate 完全不兼容。编译能过,但传给 stream().filter() 会报 Wrong type argument 错误。
典型错误现象:incompatible types: com.google.common.base.Predicate cannot be converted to java.util.function.Predicate
- 检查 import:必须是
import java.util.function.Predicate;,不是com.google.common.base.*或org.apache.commons.collections4.Predicate - Guava 的
Predicates工具类(如Predicates.notNull())不能直接喂给Stream.filter(),得包装一层:stream.filter(x -> Predicates.notNull().apply(x))—— 但没必要,Java 自带的更简洁 - 升级到 Java 8+ 后,应逐步替换掉第三方 Predicate 实现,减少抽象泄漏
真正麻烦的是那种跨模块传递 Predicate 的场景:一方用 Guava,另一方用 JDK,接口签名一碰就崩。这时候不是语法问题,是契约不统一——得约好用哪一套,别混。










