Java Function接口,用户希望实现 java.util.function.Function 接口,以便将输入参数转换为输出值,可以提供一个实现 R apply(T t) 方法的 lambda 表达式。Function 接口包含的单一抽象方法为 apply,它可以将 T 类型的泛型输入参数转换为 R 类型的泛型输出值。
Java Function接口 问题描述
用户希望实现 java.util.function.Function 接口,以便将输入参数转换为输出值。
Java Function接口 解决方案
提供一个实现 R apply(T t) 方法的 lambda 表达式。
Java Function接口 具体实例
Function 接口包含的单一抽象方法为 apply,它可以将 T 类型的泛型输入参数转换为 R 类型的泛型输出值。例 2-12 列出了 Function 接口定义的所有方法。
例 2-12
Function接口定义的方法
default <V> Function<T,V> andThen(Function<? super R,? extends V> after)
R apply(T t)
default <V> Function<V,R> compose(Function<? super V,? extends T> before)
static <T> Function<T,T> identity()
Function 最常见的用法是作为 Stream.map 方法的一个参数。例如,为了将 string 转换为整数,可以在每个实例上调用 length 方法,如例 2-13 所示。
例 2-13 将字符串映射到它们的长度
List<String> names = Arrays.asList("Mal", "Wash", "Kaylee", "Inara",
"Zoë", "Jayne", "Simon", "River", "Shepherd Book");
List<Integer> nameLengths = names.stream()
.map(new Function<String, Integer>() { ➊
@Override
public Integer apply(String s) {
return s.length();
}
})
.collect(Collectors.toList());
nameLengths = names.stream()
.map(s -> s.length()) ➋
.collect(Collectors.toList());
nameLengths = names.stream()
.map(String::length) ➌
.collect(Collectors.toList());
System.out.printf("nameLengths = %s%n", nameLengths);
// nameLengths == [3, 4, 6, 5, 3, 5, 5, 5, 13]
❶ 匿名内部类
❷ lambda 表达式
❸ 方法引用
表 2-3 列出了输入和输出泛型类型的所有基本变体。
表2-3:其他Function接口
| 接口 | 单一抽象方法 |
|---|---|
IntFunction |
R apply(int value) |
DoubleFunction |
R apply(double value) |
LongFunction |
R apply(long value) |
ToIntFunction |
int applyAsInt(T value) |
ToDoubleFunction |
double applyAsDouble(T value) |
ToLongFunction |
long applyAsLong(T value) |
DoubleToIntFunction |
int applyAsInt(double value) |
DoubleToLongFunction |
long applyAsLong(double value) |
IntToDoubleFunction |
double applyAsDouble(int value) |
IntToLongFunction |
long applyAsLong(int value) |
LongToDoubleFunction |
double applyAsDouble(long value) |
LongToIntFunction |
int applyAsInt(long value) |
BiFunction |
R apply(T t, U u) |
在例 2-13 中,由于 map 方法返回的是基本数据类型 int,该方法的参数可能是 ToIntFunction。Stream.mapToInt 方法传入 ToIntFunction 作为参数,mapToDouble 和 mapToLong 方法与之类似。
mapToInt、mapToDouble 与 mapToLong 的返回类型分别为 IntStream、DoubleStream 和 LongStream。
那么,如果输入参数和返回类型相同呢? java.util.function 包为此定义了 UnaryOperator 接口,以及相应的 IntUnaryOperator、DoubleUnaryOperator 和 LongUnaryOperator 接口,三者的输入和输出参数分别为 int、double 和 long。UnaryOperator 的一种应用是 StringBuilder 的 reverse 方法,因为输入类型和输出类型均为字符串。
BiFunction 接口定义了两个泛型输入类型和一个泛型输出类型,三者应为不同的类型。如果三者相同,可以使用 java.util.function 包定义的 BinaryOperator 接口。Math.max 就是一种二元运算符,其输入和输出为 int、double、float 或 long 型数据。相应地,java.util.function 包也定义了 IntBinaryOperator、DoubleBinaryOperator 与 LongBinaryOperator 接口。3
3有关 Java 标准库中 BinaryOperator 用法的详细讨论,请参见范例利用reduce方法实现归约操作 。
表 2-4 列出了 BiFunction 接口的所有基本变体。
表2-4:其他BiFunction接口
| 接口 | 单一抽象方法 |
|---|---|
ToIntBiFunction |
int applyAsInt(T t, U u) |
ToDoubleBiFunction |
double applyAsDouble(T t, U u) |
ToLongBiFunction |
long applyAsLong(T t, U u) |
尽管 Function 主要用于各种 Stream.map 方法,但这些方法也可能出现在其他上下文中,举例如下。
Map.computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction)
如果指定的键没有值,使用所提供的 Function 计算一个值并将其添加到 Map。
Comparator.comparing(Function<? super T,? extends U> keyExtractor)
comparing 方法生成一个 Comparator,使用给定 Function 生成的键对集合进行排序。相关讨论请参见范例 利用比较器实现排序 。
Comparator.thenComparing(Function<? super T,? extends U> keyExtractor)
thenComparing 是一种实例方法,也可以用于排序。如果集合的首次排序返回相同的值,则使用另一种机制进行排序。
此外,Function 还广泛用于分组和下游收集器(downstream collector)的 Collectors 工具类中。
有关 andThen 和 compose 方法的讨论请参见范例闭包复合。identity 方法实际上是一种简单的 lambda 表达式(e -> e),范例 将线性集合添加到映射 将介绍其中一种应用。
极客教程