持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第18天,点击查看活动详情
1. Function
Function 是 Java8 之后引入的新的接口类型,位于 java.util.function 包中,代表一种接受一个参数并有一个返回结果的函数类型。
根据 Function 的源码定义,可以看到接口上使用了 @FunctionalInterface 注解,并用到了 T,R两个泛型类型。
@FunctionalInterface
public interface Function<T, R> {
...
}
-
@FunctionalInterface 注解代表该接口是一个函数式接口
-
泛型 <T, R> 则是定义了接受参数和返回结果的类型
2. 函数式接口
2.1 函数式接口定义
Java 中一般认为标注 @FunctionalInterface 注解的接口就是为函数式接口,函数式接口可以将能用在 lambda 表达式上进行操作。
Java 中函数式接口要求接口有且只有一个抽象接口,如果一个接口中只有一个抽象方法,那么编译器在编译时会认为该接口是函数式接口,而 @FunctionalInterface 注解标注仅仅是为了让编译器更好的识别到。
-
如果接口不满足有且只有一个抽象接口,则不属于函数式接口,使用 @FunctionalInterface 注解会报错
-
接口中定义的默认方法和静态方法都不属于抽象方法,重写的 Object 类的方法也不算抽象方法
2.2 Java8 常见的函数式接口
-
Consumer,消费接口,接受一个参数,不产生返回结果
-
Predicate,断言接口,接受一个参数,并返回一个布尔类型的断言结果
-
Function,函数接口,接受一个参数,并返回一个函数结果
-
Suppiler,供给接口,不接受参数,但是返回一个结果对象
-
Runnable,无参无返回函数,不接受参数,也不返回任何结果对象
3. Function 源码
简单了解了函数式接口的定义,然后来看一下 Function 接口中定义的方法,接口定义了一个 apply() 抽象方法,两个默认方法 compose() 和 andthen() ,以及一个静态方法 identity() 。
3.1 apply() 抽象方法
Function 作为一个函数式接口,就必须满足有且仅有一个抽象方法,就是 apply() ,源码中该方法的结构为
R apply(T t);
该方法接受一个参数,并返回一个结果,参数类型和返回结果类型与 Function 的泛型类型一致,由于是抽象方法,在初始化 Function 时需要对方法进行实现,如下使用 lambda 方式创建一个 Function 类型的对象。
// 定义一个 Function 表达式对象,接受一个整数,并返回整数自身乘积
Function<Integer,Integer> func = n -> n * n;
- 由于 apply() 方法作为 Function 的抽象接口,且使用 lmabda 表达式方式实现,等号右侧的赋值逻辑就相当于对 apply() 方法的重写实现,类似如下代码实现方式
Function<Integer, Integer> func = new Function<Integer, Integer>() {
@Override
public Integer apply(Integer num) {
return num * num;
}
};
- 因此对于 func 对象,可以直接调用其 apply() 方法并传入合适的参数,方法返回值即传入参数的自身乘积
Integer result = func.apply(10);
// result 为 10 * 10 = 100
3.2 compose() 方法
compose() 方法是 Function 中的默认方法,方法中已经进行了逻辑实现,源代码如下
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
通过源码可以看到,compose() 方法接受一个非空的 Function 对象,在 compose() 方法中华最终得到一个整合的 Function 对象,该对象会执行 before 对象的 apply() 方法,然后执行当前 Function 的 apply() 方法。
因为 compose() 方法得到的是一个 Function 对象,而其中的处理逻辑即是对 apply() 方法的实现,因此想要真正执行逻辑还是需要执行对象的 apply() 方法,最终得到返回结果。
Function<Integer,Integer> func1 = n -> n * 2;
Function<Integer,Integer> func2 = n -> n * n;
Function<Integer,Integer> func1And2 = func2.compose(func1);
Integer result = func1And2.apply(3);
// 最终结果,result = (3*2) * (3*2) = 36
3.3 andthen() 方法
andthen() 方法与 compose() 方法十分相似,也是接受一个 Function 对象,并返回一个整合后的 Function 对象。
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
不同的是, andthen() 方法返回的对象中,先执行当前的 apply() 方法,然后才会执行传入参数 after 的 apply() 方法。
Function<Integer,Integer> func1 = n -> n * 2;
Function<Integer,Integer> func2 = n -> n * n;
Function<Integer,Integer> func1And2 = func2.andthen(func1);
Integer result = func1And2.apply(3);
// 最终结果,result = (3*3) * 2 = 18
3.4 identity() 方法
identity() 方法是 Function 中的一个静态方法,其实现结构也比较简单,不接受任何参数,返回一个 Function 对象,其中的 apply() 方法以参数自身作为返回结果的。
static <T> Function<T, T> identity() {
return t -> t;
}
- 使用结果展示
Integer result = Function.identity().apply(100);
// result = 100