在 java stream 中链式过滤 predicate,核心是利用 stream.filter() 方法接收一个函数式接口参数,并通过逻辑运算符组合多个条件。你可以直接传入单个 predicate 实例,或者使用 .and()、.or() 和 .negate() 方法将多个谓词连接起来,从而构建出复杂的过滤逻辑。

如何组合多个简单的过滤条件?
当需要同时满足多个条件时,应使用 Predicate.and() 方法。该方法返回一个新的 Predicate,只有当原谓词和新传入的谓词都为真时,结果才为真。这种方式比在 filter 内部写复杂的 Lambda 表达式更清晰,且易于复用。

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class Main {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
// 定义两个基础条件
Predicate<String> startsWithA = name -> name.startsWith("A");
Predicate<String> lengthGreaterThan3 = name -> name.length() > 3;
// 组合条件:以 A 开头 且 长度大于 3
Predicate<String> combined = startsWithA.and(lengthGreaterThan3);
names.stream()
.filter(combined)
.forEach(System.out::println); // 输出: Alice
}
}运行上述代码,输入列表包含 "Alice"、"Bob"、"Charlie" 和 "David"。由于 "Alice" 是唯一既以 'A' 开头又长度超过 3 的名字,因此最终结果只包含 "Alice"。如果改用 .or(),则只要满足任一条件即可通过过滤。
立即学习“Java免费学习笔记(深入)”;
如何处理取反或互斥的过滤场景?
如果需要排除某些特定条件的数据,可以使用 Predicate.negate() 方法。它返回一个逻辑相反的谓词,常用于实现“不包含”或“不等于”的逻辑。结合 .and() 或 .or(),可以构建非常灵活的互斥过滤规则。

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class Main {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
// 定义基础条件:偶数
Predicate<Integer> isEven = n -> n % 2 == 0;
// 取反:非偶数(即奇数)
Predicate<Integer> isOdd = isEven.negate();
// 过滤:保留奇数
List<Integer> result = numbers.stream()
.filter(isOdd)
.toList();
System.out.println(result); // 输出: [1, 3, 5]
}
}在此示例中,输入为 1 到 6 的整数列表。通过 isEven.negate() 得到奇数判断逻辑,过滤后结果为 [1, 3, 5]。这种链式调用方式使得逻辑表达更加语义化,避免了编写冗长的 Lambda 表达式。
基于空值安全性的具体过滤问题
在实际开发中,Stream 的数据源可能包含 null 值。如果直接使用 Predicate 中的方法引用(如 String::length),遇到 null 会抛出 NullPointerException。因此,必须确保 Predicate 内部处理了空值检查,或者在过滤前使用 Objects.nonNull()。
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
public class Main {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", null, "Bob", "");
// 安全的谓词:先检查非空,再检查长度
Predicate<String> safeLengthCheck = s -> Objects.nonNull(s) && s.length() > 3;
List<String> result = names.stream()
.filter(safeLengthCheck)
.toList();
System.out.println(result); // 输出: [Alice]
}
}输入列表包含正常字符串、null 和空字符串。由于 safeLengthCheck 使用了 Objects.nonNull(s) 作为前置条件,程序不会崩溃,而是安全地跳过了 null 和长度不足的元素,最终仅保留 "Alice"。这是处理潜在空值时的标准做法。


















