154. Java Lambda 表达式 - 总结 Java 中的四类函数式接口
java.util.function
包是 Java 8
引入的一个核心包,它在 Java
编程中扮演着重要角色。所有在 Collections Framework
或 Stream API
中使用的 lambda
表达式都实现了该包中的某个接口。
尽管 java.util.function
包中包含了很多接口,但它们可以大致分为四大类。了解这四类接口将帮助您更高效地使用函数式编程。
1. 供应者(Suppliers)
供应者接口不接收任何参数,但会返回某个结果。通常用于生成某些值或提供某些数据。
-
Supplier<T>
是供应者接口的一个例子,它的定义如下:java@FunctionalInterface public interface Supplier<T> { T get(); }
示例: 使用
Supplier
返回一个随机数:javaSupplier<Double> randomValue = () -> Math.random(); System.out.println(randomValue.get());
2. 消费者(Consumers)
消费者接口接收一个参数并执行某种操作,但不返回任何结果。它通常用于对输入进行处理,如打印或修改数据。
-
Consumer<T>
是消费者接口的一个例子:java@FunctionalInterface public interface Consumer<T> { void accept(T t); }
示例: 使用
Consumer
打印一个字符串:javaConsumer<String> print = s -> System.out.println(s); print.accept("Hello, world!");
3. 谓词(Predicates)
谓词接口接收一个参数并返回一个 boolean
值。它常用于过滤、判断条件等操作。
-
Predicate<T>
是谓词接口的一个例子:java@FunctionalInterface public interface Predicate<T> { boolean test(T t); }
示例: 使用
Predicate
检查一个字符串是否为指定长度:javaPredicate<String> isLength3 = s -> s.length() == 3; System.out.println(isLength3.test("abc")); // true System.out.println(isLength3.test("abcd")); // false
4. 函数(Functions)
函数接口接收一个参数并返回某种类型的结果。它常用于对数据进行转换。
-
Function<T, R>
是函数接口的一个例子:java@FunctionalInterface public interface Function<T, R> { R apply(T t); }
示例: 使用
Function
将字符串转换为其长度:javaFunction<String, Integer> toLength = s -> s.length(); System.out.println(toLength.apply("hello")); // 5
具有两个参数的版本
除了上述四大类函数式接口之外,还有一些接口版本,它们接受两个参数而不是一个。常见的接口包括:
BiConsumer<T, U>
:接收两个参数并执行操作,但不返回结果。BiPredicate<T, U>
:接收两个参数并返回boolean
值。BiFunction<T, U, R>
:接收两个参数并返回某个结果。
示例:使用 BiFunction
计算两个整数的和
java
BiFunction<Integer, Integer, Integer> add = (a, b) -> a + b;
System.out.println(add.apply(5, 3)); // 8
专门的版本:避免装箱和拆箱
为了提高性能,Java
提供了一些专门的接口,这些接口避免了装箱和拆箱操作。它们的命名通常与所接受的类型或返回的类型相关。
示例:专门的 IntPredicate
接口
IntPredicate
是 Predicate
的专门版本,用于处理 int
类型:
java
IntPredicate isPositive = i -> i > 0;
System.out.println(isPositive.test(5)); // true
System.out.println(isPositive.test(-1)); // false
类似地,Java
还提供了以下专门接口:
IntFunction<R>
、LongFunction<R>
、DoubleFunction<R>
:接收原始类型并返回某个类型的结果。ToIntFunction<T>
、ToLongFunction<T>
、ToDoubleFunction<T>
:接收一个对象并返回原始类型的结果。
示例:使用 ToIntFunction<T>
将字符串转换为其长度(返回 int
)
java
ToIntFunction<String> stringLength = s -> s.length();
System.out.println(stringLength.applyAsInt("hello")); // 5
对于类型相同的操作,使用 UnaryOperator<T>
和 BinaryOperator<T>
如果您有两个相同类型的参数,UnaryOperator<T>
和 BinaryOperator<T>
是 Function<T, T>
和 BiFunction<T, T, T>
的特例。
-
UnaryOperator<T>
:表示接受并返回相同类型的函数,通常用于修改或处理单一类型的数据。示例: 使用
UnaryOperator
将字符串转换为大写:javaUnaryOperator<String> toUpperCase = s -> s.toUpperCase(); System.out.println(toUpperCase.apply("hello")); // HELLO
-
BinaryOperator<T>
:表示接受并返回相同类型的两个参数,通常用于二元操作(如加法、乘法等)。示例: 使用
BinaryOperator
计算两个整数的和:javaBinaryOperator<Integer> add = (a, b) -> a + b; System.out.println(add.apply(5, 3)); // 8
总结
java.util.function
包包含了多种功能强大的接口,您可以根据需求选择合适的接口进行使用。总的来说,它们分为四类:
- 供应者(Suppliers):不接收任何参数,返回一个值。
- 消费者(Consumers):接收一个参数,不返回任何值。
- 谓词(Predicates) :接收一个参数,返回
boolean
值。 - 函数(Functions):接收一个参数,返回一个结果。
除此之外,Java 还提供了带两个参数的版本(如 BiConsumer
、BiPredicate
、BiFunction
)以及专门处理原始类型的版本,以提高性能。
通过合理使用这些函数式接口,您能够编写更加简洁、易读且高效的代码,特别是在流操作和数据转换方面。