函数编程的最直接的表现,莫过于将函数作为数据自由传递,结合泛型推导能力,使代码表达能力获得飞一般的提升。那么,Java8是怎么支持函数编程的呢?主要有三个核心概念:
在上一篇的转载博客< 深入浅出 Java 8 Lambda 表达式>里,了解了什么是Lambda表达式,什么是函数式接口,Lambda表达式的一般语法
但是我还是不太懂怎么自己开发自己的函数式接口以及怎么调用。今天在阅读Arrays源码时看到setAll方法,我明白怎么用Lambda表达式以及怎么自定义自己的函数式接口
首先setAll方法源码
public static void setAll(double[] array, IntToDoubleFunction generator) {
Objects.requireNonNull(generator);//这一行不用管,和本片的内容没有联系
for (int i = 0; i < array.length; i++)
array[i] = generator.applyAsDouble(i);
}
IntToDoubleFunction 是函数式接口源码如下,函数接口必须用注解@FunctionalInterface注解,函数式接口中有且仅有一个函数,不能没有也不能多余一个函数;这个接口的作用就是根据输入的int型value值返回一个double值。
@FunctionalInterface
public interface IntToDoubleFunction {
double applyAsDouble(int value);
}
下面是setAll方法的使用
double[] dou = new double[3];
Arrays.setAll(dou,(int i)->i*3);
System.out.println(Arrays.toString(dou))
输出
[0.0, 3.0, 6.0]
在< 深入浅出 Java 8 Lambda 表达式>里说:在 Java 中,Lambda 表达式是对象,他们必须依附于一类特别的对象类型——函数式接口(functional interface)。所以这里就可以理解为setAll的Lambda表达式就是接口IntToDoubleFunction 的一个实现类并返回了这个对象,有点像匿名内部类。按照这样的思想,setAll方法还是可以这样调用:
double[] dou = new double[3];
IntToDoubleFunction obj = new IntToDoubleFunction (){
@Override
public double applyAsDouble(int value) {
return (double)(value*3);
}
};
Arrays.setAll(dou,obj);
System.out.println(Arrays.toString(dou))
输出
[0.0, 3.0, 6.0]
结果一样,说明之前的是对的。Lambda表达式有点像匿名内部类,简化的匿名内部类。
需要注意的是Lambda表达式不同于匿名内部类,匿名内部类在编译的时候会生成相应的class字节码,但是功能相同,但是不会生成相应的class字节码;而是一个函数,反编译上面含有Lambda表达式的class字节码得到
private static double lambda$main$0(int);
descriptor: (I)D
Code:
0: iload_0
1: iconst_3
2: imul
3: i2d
4: dreturn
}
是一个静态函数,所以Lambda表达式和匿名内部类还是有区别,但是可以按照匿名内部类理解。
假如我现在要把输入的int数据转换成String,并赋给String[]数组。
首先定义函数式接口
@FunctionalInterface
interface InToString{
String inToString(int a);
}
定义类似setAll的方法
class ABC{
public void test(String[]a,InToString obj){
for(int i = 0; i < a.length; i++){
a[i] = obj.inToString(i);
}
}
}
调用上面方法
public static void main(String[] args) {
String[] dou = new String[3];
ABC.test(dou,(int i)->Integer.toString(i));
System.out.println(Arrays.toString(dou))
}
输出
[0, 1, 2]
以上就是函数式编程之函数式接口与Lambda表达式的使用。
关于函数接口,需要记住的就是两件事:
最直接的支持就是 java.util.Function 包。定义了四个最基础的函数接口:
其它的函数接口都是通过这四个扩展而来。