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

相关推荐
葡萄城技术团队5 分钟前
GcWord V8.2 新版本:TOA/TA字段增强、模板标签管理与PDF导出优化
后端
葡萄城技术团队8 分钟前
Java GcExcel V8.2 新版本:效率升级与功能突破
后端
前端fighter14 分钟前
深入解析CSS定位:Sticky与Fixed的异同与实战应用
前端·css·面试
本就是菜鸟何必心太浮18 分钟前
python中`__annotations__` 和 `inspect` 模块区别??
java·前端·python
Jerry19 分钟前
Compose Material Design 系统
前端
Coodor19 分钟前
碰一下可打开小程序,在web系统中如何嵌入将小程序写入NFC
前端·小程序·nfc
高端章鱼哥20 分钟前
很简单,MySQL安装指南
前端·mysql
雾岛听风来26 分钟前
你真的知道 Java 里的 Exception 和 Error 有啥不同吗?
前端
维维酱28 分钟前
React.memo 实现原理解析
前端·react.js
花花无缺32 分钟前
函数和方法的区别
java·后端·python