函数式编程思想
在数学中,函数就是有输入量、输出量的一套计算方案,也就是“拿什么东西做什么事情”。相对而言,面向对象过分强调“必须通过对象的形式来做事情”,而函数式思想则尽量忽略面向对象的复杂语法——强调做什么,而不是以什么形式做。
面向对象的思想:
做一件事情,找一个能解决这个事情的对象,调用对象的方法,完成事情.
函数式编程思想:
只要能获取到结果,谁去做的,怎么做的都不重要,重视的是结果,不重视过程
Lambda表达式的格式
Lambda 表达式基于数学中的 λ 演算得名,直接对应于其中的 lambda 抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数。
格式:
(形式参数列表) -> {代码块}
组成Lambda表达式的三要素:参数列表,箭头,代码块
| 要素 | 说明 | 
|---|---|
| 形式参数列表 | 如果有多个参数,参数之间用逗号隔开;如果没有参数,留空即可,实际上就是接口里面抽象方法的参数 | 
| -> | 由英文中画线和大于符号组成,固定写法。代表指向动作 | 
| 代码块 | 是我们具体要做的事情,也就是以前我们写的方法体内容 | 
eg
public class Demo04ThreadNameless {public static void main(String[] args) {new Thread(new Runnable() {@Overridepublic void run() {System.out.println("多线程任务执行!");}}).start();}}
上述 Runnable 接口的匿名内部类写法可以通过更简单的Lambda表达式达到等效
public class Demo04ThreadNameless {public static void main(String[] args) {new Thread(()->{System.out.println("多线程任务执行!");}).start();}}
Lambda 表达式对应的其实是一个 只有一个抽象方法 的接口(在 Java 中这种接口叫做功能接口)的匿名类。
无参数无返回值
public class LambdaRunnable {public static void main(String[] args) {Runnable r = new Runnable() {@Overridepublic void run() { // 方法无形参列表,也无返回值System.out.println("Hello, World");}};//匿名内部类r.run();// 通过 lambda 表达式来实例化 Runnable 接口的实现类Runnable l = () -> System.out.println("Hello, Lambda");l.run();}}
单参数无返回值
public class ConsumerLambda {public static void main(String[] args) {// 单参数无返回值Consumer<String> c = new Consumer<String>() {@Overridepublic void accept(String s) {System.out.println(s);}};c.accept("Hello World!");Consumer<String> l = (String s) -> {System.out.println(s);};l.accept("你好,世界!");}}
有参有返回值
操作步骤
给定一个计算器 Calculator 接口,内含抽象方法 calc 可以将两个int数字相加得到和值:
public interface Calculator {int calc(int a,int b);}
示例代码
public class Demo08InvokeCalc {private static void invokeCalc(int a, int b, Calculator calculator) {int result = calculator.calc(a, b);System.out.println("结果是:" + result);}public static void main(String[] args) {invokeCalc(1,2,(int a,int b)->{return a+b;});}}
省略的规则
省略数据类型
小括号内参数的类型可以省略;
public static void main(String[] args) {invokeCalc(1, 2, (a, b) -> {return a + b;});}
省略参数的小括号
如果小括号内有且仅有一个参,则小括号可以省略;
Consumer<String> l = (String s) -> {System.out.println(s);};l.accept("Hello World");Consumer<String> la = s -> {System.out.println(s);};la.accept("Hello Lambda");
省略 return 和大括号
如果大括号内有且仅有一个语句,则无论是否有返回值,都可以省略大括号、return关键字及语句分号。
public static void main(String[] args) {invokeCalc(1,2,(a,b)-> a+b);}
比较判断
public class LambdaReturn {public static void main(String[] args) {// 省略 return 和 {} 前代码Comparator<Integer> comparator1 = (o1, o2) -> {return o1.compareTo(o2);};System.out.println(comparator1.compare(1, 2));// 省略 return 和 {} 后代码Comparator<Integer> comparator2 = (o1, o2) -> o1.compareTo(o2);System.out.println(comparator2.compare(3, 2));}}
注意事项
Lambda的语法非常简洁,完全没有面向对象复杂的束缚。但是使用时有几个问题需要特别注意:
- 使用Lambda必须具有接口,且要求接口中有且仅有一个抽象方法。
无论是JDK内置的 Runnable 、 Comparator 接口还是自定义的接口,只有当接口中的抽象方法存在且唯一时,才可以使用Lambda。 - 使用Lambda必须具有上下文推断。
也就是方法的参数或局部变量类型必须为Lambda对应的接口类型,才能使用Lambda作为该接口的实例。 
备注:有且仅有一个抽象方法的接口,称为“函数式接口”。
Lambda表达式和匿名内部类的区别
所需类型不同
匿名内部类:可以是接口,也可以是抽象类,还可以是具体类
Lambda表达式:只能是接口
使用限制不同
如果接口中有且仅有一个抽象方法,可以使用Lambda表达式,也可以使用匿名内部类
如果接口中多于一个抽象方法,只能使用匿名内部类,而不能使用Lambda表达式
实现原理不同
匿名内部类:编译之后,产生一个单独的.class字节码文件
Lambda表达式:编译之后,没有一个单独的.class字节码文件。对应的字节码会在运行的时候动态生成
