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
如果需要测试原始类型(如 int
、long
或 double
),JDK
提供了专门的 Predicate
接口来避免自动装箱的性能开销。与 Predicate<T>
一样,这些接口的抽象方法也叫 test()
,但是它们针对的是原始类型。
例如,您可以使用 IntPredicate
来测试整数值:
java
IntPredicate isGreaterThan10 = i -> i > 10;
在上面的示例中,IntPredicate
用于判断整数是否大于 10,它避免了装箱和拆箱的开销。
IntPredicate
、LongPredicate
和 DoublePredicate
这三个接口分别用于处理 int
、long
和 double
类型的数据:
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
提供了专门的谓词接口,如IntPredicate
、LongPredicate
和DoublePredicate
,用于处理原始类型数据。 BiPredicate<T, U>
接口:用于测试两个参数,并根据条件返回布尔值。removeIf()
方法 :removeIf()
是集合框架中一个非常实用的方法,可以结合Predicate
对集合进行筛选和删除操作。
通过理解并灵活运用 Predicate
接口,您可以写出更简洁、灵活且高效的条件判断逻辑,特别是在流操作和集合操作中。