Java 函数接口Function详解与示例【函数接口Function】
Java 8引入了一种新的函数式编程风格,Function接口是Java函数式编程中最重要的四个函数式接口之一。
Function 函数式接口实现的功能:接受一个输入参数,然后产生一个输出结果。
Function接口在java.util.function包中定义,它的源码如下:
package java.util.function;
import java.util.Objects;
@FunctionalInterface
public interface Function<T, R> {
/**抽象方法*/
R apply(T t);
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
static <T> Function<T, T> identity() {
return t -> t;
}
}
Function 接口是非常有用的,它是Java函数式编程中最重要的四个函数式接口中使用最为广泛的。
用途一:函数转换
Function可以用于将一个类型的值转换为另一个类型的值。它可以用于各种转换操作,如类型转换、数据映射map等。
用途二:数据处理
Function 可用于对输入数据进行处理并生成输出结果。它可以用于执行各种操作,如过滤filter、计算、提取、格式化等。
Function接口定义的方法:
使用andThen方法将多个函数应用于同一个输入:
Function<String, String> function1 = s -> s + " world";
Function<String, String> function2 = s -> s + "!";
Function<String, String> combined = function1.andThen(function2);
String result = combined.apply("Hello"); // 结果为 "Hello world!"
使用方法compose()将多个函数应用于同一个输入,但是顺序与方法andThen()的作用刚好相反:
Function<String, String> function1 = s -> s + " world";
Function<String, String> function2 = s -> s + "!";
/***注意:这里故意调换了两个函数的调用顺序***/
Function<String, String> combined = function2.compose(function1);
String result = combined.apply("Hello"); // 结果为 "Hello world!"
Function函数接口的方法identity()是一个直接返回入口参数的方法(函数,Lambda表达式对象),等价于形式如:t -> t 形式的Lambda表达式。一看感觉没啥用处,其实它在某些场景大有用处,例如:作为默认函数,可以作为函数组合链中的起点或默认函数。
保持一致性,在某些情况下,我们可能需要一个函数,但不需要对输入进行任何操作。使用方法 identity() 可以确保函数的签名(输入和输出类型)与其函数一致。
当我们使用Stream时,要将流中元素转换成其他容器或Map时,就会使用到Function.identity()。例如:
Stream<String> stream = Stream.of("This", "is", "a", "test");
Map<String, Integer> map = stream.collect(Collectors.toMap(Function.identity(), String::length));
Function.identity()应用示例
下面的代码中,Task是一个对象,它包含Title等属性,Task::getTitle可获取task实例的标题作为Map的key,我们把task对象本身作为Map的value。task -> task是一个用来返回输入参数自身的Lambda表达式。
我们来对比一下,使用Lambda表达式和使用Function.identity()方法的用法:
/***使用Lambda表达式实现的版本***/
private static Map<String, Task> taskMap(List<Task> tasks) {
return tasks.stream().collect(toMap(Task::getTitle, task -> task));
}
可以使用Function接口中的静态方法identity()来让上面的代码代码变得更简洁明了、传递开发者意图时更加直接。使用Function.identity()方法的写法:
/***使用Function.identity()方法实现的版本***/
import static java.util.function.Function.identity;
private static Map<String, Task> taskMap(List<Task> tasks) {
return tasks.stream().collect(toMap(Task::getTitle, identity()));
}
Function.identity() 和 Lambda表达式( t->t ) 的区别的应用示例
下面三种写法实现相同功能,这是Function.identity() 和 Lambda表达式( t->t )可以互相替代的情形:
/***写法一***/
Arrays.asList("How", "much", "is","the","apple")
.stream()
.collect(Collectors.toMap( str -> str, str->str.length()));
/***写法二,Lambda表达式( t->t )版本***/
Arrays.asList("How", "much", "is","the","apple")
.stream()
.map(str -> str) //Lambda表达式( t->t )
.collect(Collectors.toMap(str -> str,str->str.length())); //String::length
/***写法三,Function.identity()版本***/
Arrays.asList("How", "much", "is","the","apple")
.stream()
.map(Function.identity()) //Function.identity()版本
.collect(Collectors.toMap( Function.identity(), String::length));
下面看一种 Function.identity() 和 Lambda表达式( t->t )不能互相替代的情形:
这儿使用 Lambda表达式( t->t )可行:
int[] iArr = Arrays.asList(5, 9, 12,3).stream().mapToInt(t->t).toArray();
但是,如下使用 Function.identity() 是不行的:
int[] iArr = Arrays.asList(5, 9, 12,3).stream().mapToInt( Function.identity() ).toArray();
为什么不行呢?其本质是 Function.identity(), Function<T, T> identity() 恒等式函数identity(),返回输入参数本身。输入是Integer对象,返回的还是Integer对象。
而映射器mapToInt()需要返为基本数据类型的IntStream。
而上面的Lambda表达式( t->t )在映射器 mapToInt(t->t) 中能把Integer对象自动拆箱变成int,从而产生IntStream。
Function.identity() 不适用于 mapToInt()、mapToLong()、mapToDouble() 等需要进行拆箱操作的场景。
Function接口的应用实例
使用Function接口作为方法的参数:
void process(Function<String, String> function, String input) {
String result = function.apply(input);
System.out.println(result);
}
process(s -> s + "!", "Hello"); // 输出 "Hello!"
使用Java 8的Stream API进行映射:
List<String> strings = Arrays.asList("a", "b", "c");
List<String> results = strings.stream()
.map(s -> s + "!")
.collect(Collectors.toList());
// 结果为 ["a!", "b!", "c!"]
Function函数接口有一大家族,如下所示:
参考文献:
【Java函数篇】Java8中函数接口Function使用详解
Java 8 Function 函数接口
Function.identity()的使用详解
Java8中Function函数式接口详解及使用
Java8中Function接口的使用方法详解
Java 8 新特性—函数式接口
作者:Java编程乐园