152. Java Lambda 表达式 - 深入理解 Java 的 Predicate 接口及其高效用法

152. Java Lambda 表达式 - 深入理解 Java 的 Predicate 接口及其高效用法

Predicate<T> 是 Java 中的一个功能接口,它用于对对象进行测试,返回一个布尔值。通常,Predicate<T> 用于流 API 中的过滤操作,也可以在各种场景中进行条件判断。

Predicate<T> 接口的定义

Predicate<T> 接口的抽象方法是 test(T t),它接受一个类型为 T 的参数,并返回一个布尔值,表示该对象是否满足特定的条件:

java 复制代码
@FunctionalInterface
public interface Predicate<T> {
    boolean test(T t);
}
示例:使用 Predicate<String> 测试字符串的长度
java 复制代码
Predicate<String> length3 = s -> s.length() == 3;

这个 Predicate 会检查传入的字符串是否长度为 3。您可以使用 test() 方法来测试一个字符串是否符合该条件:

java 复制代码
String word = "Java";
boolean isOfLength3 = length3.test(word);
System.out.println("Is of length 3? " + isOfLength3);

输出结果:

java 复制代码
Is of length 3? false
使用专用的Predicate

如果需要测试原始类型(如 intlongdouble),JDK 提供了专门的 Predicate 接口来避免自动装箱的性能开销。与 Predicate<T> 一样,这些接口的抽象方法也叫 test(),但是它们针对的是原始类型。

例如,您可以使用 IntPredicate 来测试整数值:

java 复制代码
IntPredicate isGreaterThan10 = i -> i > 10;

在上面的示例中,IntPredicate 用于判断整数是否大于 10,它避免了装箱和拆箱的开销。

IntPredicateLongPredicateDoublePredicate

这三个接口分别用于处理 intlongdouble 类型的数据:

  • IntPredicate:接受一个 int 类型的参数并返回一个布尔值。
  • LongPredicate:接受一个 long 类型的参数并返回一个布尔值。
  • DoublePredicate:接受一个 double 类型的参数并返回一个布尔值。

这些专用Predicate的性能要比通用的 Predicate<T> 更高效,尤其是在处理大量数据时。

示例:使用 IntPredicate 测试整数值是否大于 10
java 复制代码
IntPredicate isGreaterThan10 = i -> i > 10;
boolean result = isGreaterThan10.test(15);
System.out.println("Is 15 greater than 10? " + result);

输出:

java 复制代码
Is 15 greater than 10? true

使用 BiPredicate<T, U> 测试两个元素

除了 Predicate<T>JDK 还提供了 BiPredicate<T, U> 接口,用于测试两个参数。这个接口的定义如下:

java 复制代码
@FunctionalInterface
public interface BiPredicate<T, U> {
    boolean test(T t, U u);
}

BiPredicate 接口非常适合用于需要对两个参数进行条件判断的场景。它的抽象方法 test(T t, U u) 接受两个参数并返回一个布尔值。

示例:使用 BiPredicate<String, Integer> 测试字符串的长度是否匹配指定值
java 复制代码
BiPredicate<String, Integer> isOfLength = (word, length) -> word.length() == length;

在这个示例中,isOfLength 是一个 BiPredicate,它接受一个字符串和一个整数,并判断字符串的长度是否等于指定的整数。

调用这个 BiPredicate

java 复制代码
String word = "Java";
int length = 4;
boolean isWordOfLength4 = isOfLength.test(word, length);
System.out.println("Is the word of length " + length + "? " + isWordOfLength4);

输出:

java 复制代码
Is the word of length 4? true

需要注意的是,BiPredicate<T, U> 没有提供处理原始类型的专用版本,因此在需要处理原始类型时,您仍然需要使用通用的 Predicate 接口或其他专用Predicate口。

Predicate传递给集合

在集合框架中,removeIf() 方法是一个非常有用的方法,它接受一个 Predicate<T> 作为参数,测试集合中的每个元素。如果元素满足Predicate条件,removeIf() 方法会将其移除。

示例:使用 Predicate<String> 过滤字符串集合
java 复制代码
List<String> immutableStrings = List.of("one", "two", "three", "four", "five");
List<String> strings = new ArrayList<>(immutableStrings);
Predicate<String> isEvenLength = s -> s.length() % 2 == 0;
strings.removeIf(isEvenLength);
System.out.println("Filtered strings: " + strings);

运行上面的代码,将输出:

java 复制代码
Filtered strings: [one, two, three]
注意事项:
  • removeIf() 会修改原集合,因此不应在不可变集合上调用,例如使用 List.of() 创建的集合。如果尝试在不可变集合上调用 removeIf(),将抛出 UnsupportedOperationException
  • 使用 Arrays.asList() 返回的列表可以修改其现有元素,但不允许添加或删除元素。调用 removeIf() 时将会失败。

总结

  • Predicate<T> 接口:用于测试一个对象,返回布尔值。它在过滤操作和条件判断中非常常见。
  • 专用Predicate接口 :为了避免性能损失,JDK 提供了专门的谓词接口,如 IntPredicateLongPredicateDoublePredicate,用于处理原始类型数据。
  • BiPredicate<T, U> 接口:用于测试两个参数,并根据条件返回布尔值。
  • removeIf() 方法removeIf() 是集合框架中一个非常实用的方法,可以结合 Predicate 对集合进行筛选和删除操作。

通过理解并灵活运用 Predicate 接口,您可以写出更简洁、灵活且高效的条件判断逻辑,特别是在流操作和集合操作中。

相关推荐
jingling5553 分钟前
Git 常用命令指南:从入门到高效开发
前端·javascript·git·前端框架
程序员爱钓鱼3 分钟前
Go语言实战案例:使用WaitGroup等待多个协程完成
后端·go·trae
索西引擎4 分钟前
【前端】网站favicon图标制作
前端
程序员海军11 分钟前
告别低质量Prompt!:字节跳动PromptPilot深度测评
前端·后端·aigc
程序员爱钓鱼12 分钟前
Go语言实战案例:任务调度器:定时执行任务
后端·go·trae
华洛12 分钟前
关于可以控制大模型提升任意产品的排名这件事📈
前端·github·产品经理
Yanc14 分钟前
翻了vue源码 终于解决了这个在SFC中使用tsx的bug
前端·vue.js
nujnewnehc18 分钟前
失业落伍前端, 尝试了一个月 ai 协助编程的真实感受
前端·ai编程·github copilot
沙蒿同学18 分钟前
Golang单例模式实现代码示例与设计模式解析
后端·go
Apifox19 分钟前
如何在 Apifox 中给字段设置枚举(比如字符串、数组等)?
后端·ai编程·测试