Java基础学习之函数式编程Function接口(JDK8)

前言

hello大家好,好久不见,前两天把手里的项目进度提了一下,今天有时间来继续复习JAVA基础了。今天的主角就是Function接口,老规矩先把源码贴出来。


1.源码

package java.util.function;

import java.util.Objects;

@FunctionalInterface
public interface Function<T, R> {
    R apply(T var1);

    default <V> Function<V, R> compose(Function<? super V, ? extends T> var1) {
        Objects.requireNonNull(var1);
        return (var2) -> {
            return this.apply(var1.apply(var2));
        };
    }

    default <V> Function<T, V> andThen(Function<? super R, ? extends V> var1) {
        Objects.requireNonNull(var1);
        return (var2) -> {
            return var1.apply(this.apply(var2));
        };
    }

    static <T> Function<T, T> identity() {
        return (var0) -> {
            return var0;
        };
    }
}

看过前两篇文章的同学们应该有印象,Consumer和Predicate接口都只有一个T作为一个输入泛型,而现在看起来Function接口是有一个T输入泛型和一个R输出泛型,关于泛型我稍微的再介绍一下。

(1)泛型类

泛型类使用<T>来表示该类为泛型类,其内部成员变量和函数的返回值都可以为泛型<T> ,Function源码的标识为<T,R>,也就是两个泛型参数,此处不再赘述,具体泛型类可以看网上的文章。

(2)泛型方法和通配符

在方法修饰符的后面加一个<T>表明该方法为泛型方法,如Function 的源码里的compose方法的<V>。通配符也很好理解,还是compose的例子,我们可以看到compose的参数为一个Function类型,其中Functin的参数指定了其第一个参数必须是V的父类,第二个参数必须继承T,也就是T的子类。

2. compose 和 andThen

其实对于Function接口来说,本身就是一个“处理工厂”的概念,它的意义在于我写了一个Function,意味着我准备把这个输入的“泛型”通过“某种处理”来输出其他“泛型”。这个接口是最能提现出JAVA8的函数式编程思想的,例如

y = f(x)

只不过在java中我先把函数写出来,然后再通过lambda表达式传入具体函数的实现方法。接下来我们对一个整数进行两个Function操作:

1. 将该int类型的数乘以10;

2. 将该int类型的数减去5;

package mytest;


import java.util.function.Function;

public class StringBuilderTest {
    public static void main(String[] args) {
        //将数乘10
        Function<Integer, Integer> function1 = integer -> integer * 10;
        //将数减5
        Function<Integer, Integer> function2 = integer -> integer - 5;

        System.out.println(function1.compose(function2).apply(10));
        System.out.println(function1.andThen(function2).apply(10));
    }


}

上面我们分别使用了compose和andThen方法,大家大可自己猜测一下两个结果是什么。

50
95

3. identity

这是一个静态方法,意味着可以使用 Function.identity() 这种方法调用。

static <T> Function<T, T> identity() {
        return (var0) -> {
            return var0;
        };
    }

这个方法返回的是 t -> t 的一个lambda表达式,有种“如蜜传如蜜”的感觉,哈哈哈哈。具体可以使用在哪儿呢?

下面的代码中,Task::getTitle需要一个task并产生一个仅有一个标题的key。task -> task是一个用来返回自己的lambda表达式,上例中返回一个task。


private static Map<String, Task> taskMap(List<Task> tasks) {

return tasks.stream().collect(toMap(Task::getTitle, task -> task));

}
可以使用Function接口中的默认方法identity来让上面的代码代码变得更简洁明了、传递开发者意图时更加直接,下面是采用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()));
}

作为函数式编程的第三个接口,特点就是“有两个入参,分别确定入参和出参的泛型,返回一个类”。

下一章我们继续学习Supplier接口


版权声明:本文为zhangqx1994原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。