Java8 新特性之 Function

193 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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