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 接口,您可以写出更简洁、灵活且高效的条件判断逻辑,特别是在流操作和集合操作中。

相关推荐
朱 欢 庆17 分钟前
云服务器附件备份到本机内网服务器
运维·服务器·前端·经验分享
jyOverQ19 分钟前
RabbitMQ 消息积压怎么办?Prefetch、消费者并发与扩容
分布式·后端·rabbitmq
支支დ6 小时前
VO by Vercel 前端特定优势:为什么它是构建 AI 应用的新范式
前端·人工智能
香芋芋圆6 小时前
AI 冲击内卷之下,普通前端如何破局?WebGIS—— 低门槛突围赛道
前端·javascript·人工智能·学习·职场发展
INS_KF7 小时前
【编程笔记】成员函数中两个 const 的区别(const Data &getData() const;)
前端·javascript·笔记
宿6747 小时前
vue3-async
前端·javascript·vue.js
YXWik67 小时前
记录前端请求接口在浏览器请求响应的Preview和Response展示的一样的问题
前端
2501_928996227 小时前
GPT-4o换DeepSeek迁移成本多少?中科热备解析API聚合平台技术账本
前端·数据库·人工智能
东风破_7 小时前
从跨域到 WebSocket:前端跨域方案、SSE 与双向实时通信详解
前端·后端
原则猫8 小时前
TS 类型工具
前端