1.前言
最近在看《Java 函数式编程》这本书
但在第二章就把我难到了。。。。
写这篇文章的目的是让我或者最好是可以让大家都能理解下面这个编程的写法:
static <T, U, V> Function<Function<U, V>, Function<Function<T, U>, Function<T, V>>> higherCompose() {
return x->y->z-> x.apply(y.apply(z));
}
就是这玩意,理解了一遍又一遍,在这里写下来,希望加深自己的理解,也希望帮到大家
2.背景
首先下面这些都与Function这个接口相关,这里将Function的核心源码贴出来,如下
@FunctionalInterface
public interface Function<T, R> {
/**
* Applies this function to the given argument.
* @param t the function argument
* @return the function result
*/
R apply(T t);
}
3.从简单到复杂
3.1.实现一个简单的Function 对原数字+2
首先上面这个东西本质上是一个对象,后面的部分就是对这个对象的实现,是不是感觉有点扯,但从最简单的来说,它是这样的:
public static void main(String[] args) {
Function<Integer,Integer> f=new Function<Integer, Integer>() {
@Override
public Integer apply(Integer o) {
return o+2;
}
};
f.apply(2);
}
Function 是一个接口,实现该接口需只要实现apply方法(所以它是一个函数式接口,即该接口只需要实现一个方法),那么以上这个就很好理解了,可以这么说,它定义了这样的方法传入一个Integer,并返回一个Integer,但具体实现是交给开发人员的,接下来,进一步简化上面的式子
Function<Integer,Integer> f=a->{
return a+2;
};
System.out.println(f.apply(2));
这里也还算好理解,a可以理解为参数值,我们要做的就是参数值+2;其中方法体 较为简单,可以直接返回,还可以进一步简化成这样
Function<Integer,Integer> f=a->a+2;
System.out.println(f.apply(2));
扩展,所以Runnable的实现可以这么写
Runnable run=()-> System.out.println("线程运行了!");
new Thread(run).start();
Runable 接口也是一个函数式接口,run方法是一个void类型的,且不需要传参,所以箭头前是一个()表示不需要传参,后面是run方法的方法体
3.2.实现Function<Integer,Function<Integer,Integer>>进行两数相加
从最简单的开始,如果要实现一个两数的相加,我们可以定义一个这样的方法:
public Integer add (Integer a,Integer b){
return a+b;
}
接下来对这个方法进行函数柯里化,柯里化就是把多个参数的函数转换为只有一个参数的函数,其目的是使一个函数进行流式的编程 如下方f.apply(2).apply(3)
。 简单说柯里化,原来是f(a,b)={a+b},现在是g(a)(b),即g(a) 返回的是一个方法,即g(a)返回一个f(b)=a+b。
对应到Function<Integer,Function<Integer,Integer>>,我们认为第一个参数是一个Integer,返回的是一个Function<Integer,Integer>,以便用于第二次函数的处理,同时返回的Function<Integer,Integer>也需要我们去定义;那么下面是这个Function的实现
Function<Integer,Function<Integer,Integer>> f=x->y->x+y;
System.out.println(f.apply(2).apply(3));
可以看出f.apply(2)返回的是一个Function对象,可以继续使用该对象的 .apply方法,为了方便理解,也可以这么拆解
Function<Integer,Function<Integer,Integer>> f=
//本身是一个function,传入一个a,这个a值是不需要变化的,第一步中不需要对它进行操作
a->{//这里需要返回一个Function<Integer,Integer>
//这个function传入一个b,并与a相加,此时的a实际上已经被传入了,相当于是一个常量
return b->{
return b+a;
};
};
System.out.println(f.apply(2).apply(3));
3.3 实现Function<Function<Integer,Integer>,Function<Integer,Integer>> higerFunction 对一个数,先*2 后进行平方。
从标题来看,我们要实现这个Function接口,分析其需要传入一个Function的实现,并返回一个Function实现。
我们在实现Function时,我们只关注传进来的值怎么用,并不关注,传进来的值是怎么实现的,那么就是说如果要使用这个higerFunction 首先需要实现一个Function<Integer,Integer>那么这个实线具体是干什么?我们里边其实只有两个要点,一个是乘,一个是平方,这里可以随意定义,如果是平方:
//定义了一个平方的函数,这个函数调用apply(a)方法,会对a平方
Function<Integer, Integer> mult = a -> a * a;
Function<Function<Integer, Integer>, Function<Integer, Integer>> higerFunction =
a -> b -> a.apply(b * 2);
System.out.println(higerFunction.apply(mult).apply(5));
当然如果mult定义为乘2也是可以的如下
Function<Integer, Integer> mult = a -> a *2;
Function<Function<Integer, Integer>, Function<Integer, Integer>> higerFunction =
a -> b -> a.apply(b)*a.apply(b);
System.out.println(higerFunction.apply(mult).apply(5));
以上 实现方法体中的 a 都可以理解为是一个Function<Integer, Integer> 对象,b则是返回的Function<Integer, Integer>中的入参
3.4 实现 Function<Function<U, V>, Function<Function<T, U>, Function<T, V>>>
static <T, U, V> Function<Function<U, V>, Function<Function<T, U>, Function<T, V>>> higherCompose() {
return x->y->z-> x.apply(y.apply(z));
}
拆解来看,我们可以这样看这个结构
static <T, U, V> Function<Function<U, V>, Function<Function<T, U>, Function<T, V>>> higherCompose() {
return x->{//Function<U, V>
return y->{//Function<T, U>
return z->{//T
return x.apply(y.apply(z));
};
};
};
// throw new RuntimeException("To be implemented.");
}