Java函数式编程:一、函数式接口,lambda表达式和方法引用

Java函数式编程什么是函数式编程
通过整合现有代码来产生新的功能 , 而不是从零开始编写所有内容 , 由此我们会得到更加可靠的代码 , 并获得更高的效率
我们可以这样理解:面向对象编程抽象数据 , 函数式编程抽象行为 。
通常而言 , 方法会根据所传递的数据产生不同的结果 , 但如果想让一个方法在每次调用时都有不同的表现该怎么办?你可能会想到多态 , 没错 , 多态是一种通过改变实际执行的方法所属对象 , 以此来改变实际执行的方法代码的方式 , 许多框架实现IoC本质上也是实现了一种自动化的多态 。而这里我们要聊聊其他的两种方法 。
如果我们直接将代码传递给方法 , 就可以控制其行为 , Java 8以后 , 我们可以通过lambda表达式和方法引用这两个新的方法来实现这一点 。
1、函数式接口什么是函数式接口
什么是函数式接口?这是我们理解Lambda表达式以及方法引用的重点 , 这些接口是lambda表达式和方法引用的目标类型 , 这里我们引用一个比较容易理解的说法:函数式接口是一个只有一个抽象方法 (不包含祖先类Object中的公共方法 , 如hashcode()等) 的接口 。
当我们在编写接口时 , 这种函数式方法模式可以使用@FunctionalInterface注解来强制实施 , 如果被注解的接口不符合标准那么就会在编译时报错 。下面给出例子:
interface Functional{// 是函数式接口String speak();}interface NoFunctional{// 不是函数式接口String speak();String laugh();}interface IsFunctional{// 是函数式接口 , 因为toString()是Object祖先类的公共方法 , 不算在内String spaek();String toString();}它们的意义是什么呢?
这里拿出一个例子:
interface Say{void say();}class Speaker{public static void speak(){System.out.println("Hello, my friend!");}public static void main(String[] args){Say say = Speaker::speak; // 这里的::表示我们引用了Speaker类的speak方法say.say();// 输出Hello, my friend!}}很神奇是不是?我们直接将一个方法引用赋给了一个接口的对象 。这里初看的话显然问题一堆 , 首先方法怎么能作为对象赋值 , 其次该类也没有实现该接口 , 最后 , 就算能说通 , 我们的接口和Speaker类根本没有相同的方法啊!怎么就调用say.say()效果等同于Speaker.speak()呢?
重要:这是Java 8增加的一个小魔法:如果我们将一个方法引用或一个lambda表达式赋给一个函数式接口(且两个方法的返回值类型和参数类型可以匹配上 , 方法名并不重要) , 那么Java会自动调整这个赋值操作 , 使其能够匹配目标接口 。对于底层来说 , 这里是Java编译器创建一个实现了目标接口的类的实例 , 并将我们的方法引用或lambda表达式包裹在其中 。
事实上 , 很容易预见 , 在这里如果我们直接将一个Speaker对象赋给一个Say接口 , 那么是无法做到的 , 因为Speaker虽然符合Say的模式 , 但却没有显式的实现Say接口 。幸运的是 , Java 8的函数式接口允许我们直接把一个实例方法赋给这样的一个接口 , 这样语法更好 , 更简单 。
Java为我们准备了大量的函数式接口 , 这样我们就可以尽量避免自己创建大量的接口 , 这些接口都可以在

经验总结扩展阅读