# Lambda表达式
![Lambad](https://img-blog.csdnimg.cn/20200903212309556.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDE4NDk5MA==,size_16,color_FFFFFF,t_70#pic_center)
Lambda表达式是JDK8引入的一个新特性,又名匿名函数或闭包,可以不用创建显示的标识符(变量名,函数名,类名等)来书写需要的代码。
java作为一门面向对象的语言,对语法有着严格的要求,在java中”一切皆对象“。但是有时候随着我们写的代码多了又发现写java代码有时候会显得复杂。比如我们每次在写代码时都需创建一个类,用到该类时又要创建该类的实例。有时候我们仅仅只是需要一个功能就能实现我们想要的目的,而不想要去和任何对象绑定在一起。例如定义一个方法,在需要的时候直接使用该方法就行了,就跟C语言这门面向过程的函数定义一样。在C++和python中是同时支持面向过程与面向对象的,不用在写代码的时候每次都需要创建一个类。
**直接使用方法的思想**就是一种函数式编程的思想。这里的“方法”和"函数"并没有太大的区别,很多时候,“方法”这个名词用在面向对象的编程语言中,而“函数”更多用在面向过程的编程语言中,例如C语言。“方法”和“函数”在抽象的层面上讲,都是接受用户的输入,处理数据,最后产生相应的结果。
总之,JDK8中引入的Lambda表达式就是为了能够让我们在一些情况下书写出更简洁的代码。下面举例说明
## 使用Lambda表达式
### 复杂的代码
在创建多线程的方法中,我们有以下方法来创建一个线程,即使用Runnable接口重写run方法来实现
```java
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("这是一个匿名内部类");
}
});
thread.start();
//也可以
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("这是一个匿名内部类");
}
}).start();
```
### 简洁的代码
从上面可以发现,其实我们代码只想执行 System.out.println("这是一个匿名内部类");这一条语句而已,然而每次创建一个线程时需要创建一个Runnable接口的实现对象,就是因为这是按照“面向对象”的编程思想实现的。如果使用Lambda表达式的方法的代码就简洁了许多。
```java
new Thread(()->{
System.out.println("这是一个匿名内部类");
}).start();
```
**Lambda语法**
Lambda表达式的基本语法如下
> () -> {}
1. 前面的一对小括号 **()** 即为run方法的参数,这里run方法本身就不用传递任何参数。
2. 中间的 -**>** 表示将前面的参数传递给后面{}中的代码。
3. **{}** 即表示run方法执行的代码体。
其标准的格式即为:
```java
(参数类型 参数名称...) -> {
//方法执行的代码
}
```
## Lambda表达式的省略
Lambda表达式在上述标准的格式下还能进一步的进行省略,可省略的情况如下
- 小括号内的参数类型可以省略。
java是强类型语言,在方法是不允许省略参数的类型的。但是在Lambda表达式中参数的类型是可以省略的,这是得益于java的推测机制,可以通过上下文推断出该变量是什么类型。
- 如果小括号内**只有一个参数**,则可以将括号也给省略了;例如
```java
name -> {System.out.println(name);}
```
个人觉得这个和上面那个省略一起用程序会比较可读一些,即在只有一个参数的情况下省略变量的类型和括号,有多个参数的情况下变量类型就不要省略了。
- 如果花括号内**有且仅有一条语句**,则无论是否有返回值,可将花括号,return关键字,语句的分号一起省略了;例如
```java
name -> System.out.println(name)
```
## 什么情况下使用Lambda表达式
虽说使用Lambda表达式可以让代码更加简洁,但是并不能够用在任意的场景下的。就像上面举的例子,用来替换Runnable接口的匿名实现类。即在使用时仍然是要存在一个接口,并且该接口中只有一个方法,不然我们直接用个 **()** 怎么知道调用哪个方法呢?当然这里值得一提的是,匿名实现类在编译的时候仍然会创建该类的.class文件。而Lambda表达式并不会,用反编译的方法发现Lambda表达式被封装成主类的一个私有方法,具体请看<a href='https://objcoding.com/2019/03/04/lambda/'>关于java Lambda这篇就够了</a>.
同样的,在JDK8中另外一个新特性函数性接口的概念可以和Lambda表达式很好的配合使用起来。
### 函数性接口
这种接口内部只有一个抽象方法待实现(可以有一些默认 default 的方法),例如Runnable接口就只有一个run()方法待实现。Comparator接口中只有一个compare()方法,其他的方法均用default修饰,或static修饰(除了继承自Object的方法)。
该接口定义举例
```java
@FunctionalInterface
public interface MyFunctionInterface {
public abstract void method();
}
```
**@FunctionalInterface** 注解可以在编译时期将该接口看成是一个函数性接口,加上该注解后如果在该接口中定义了多个抽象方法,就会报错,加上该注解也可以让人很明了这是一个函数性接口。
用lambda实现该接口中的method()方法:
```java
public class Demo {
/*
* 定义一个方法,将自定义的接口作为参数进行传递
*/
public static void show(MyFunctionInterface myFunctionInterface) {
myFunctionInterface.method();
}
public static void main(String[] args) {
show(() -> {
System.out.println("使用lambda表达式重写接口中的抽象方法!");
});
}
}
```
可见,使用Lambda表达式一般都是将一个函数性接口作为一个参数传递给一个方法(构造方法也行),然后使用Lambda表达式实现该接口对应的抽象方法。
关于函数性接口,java定义了一些常用的供我们配合Lambda使用,在java.util.function包中。
## 小结
1. 当匿名类为函数式接口时,可以考虑用Lambda表达式简化代码的书写;
2. 虽说Lambda表达式体现了函数式编程思想,但是java还是严格的使用面向对象的思想,所以Lambda表达式并不能任意供我们使用;
3. Lambda表达式的出现是java向 “写更少,做更多” 迈进的巨大一步。
- 第一章 Java基础
- ThreadLocal
- Java异常体系
- Java集合框架
- List接口及其实现类
- Queue接口及其实现类
- Set接口及其实现类
- Map接口及其实现类
- JDK1.8新特性
- Lambda表达式
- 常用函数式接口
- stream流
- 面试
- 第二章 Java虚拟机
- 第一节、运行时数据区
- 第二节、垃圾回收
- 第三节、类加载机制
- 第四节、类文件与字节码指令
- 第五节、语法糖
- 第六节、运行期优化
- 面试常见问题
- 第三章 并发编程
- 第一节、Java中的线程
- 第二节、Java中的锁
- 第三节、线程池
- 第四节、并发工具类
- AQS
- 第四章 网络编程
- WebSocket协议
- Netty
- Netty入门
- Netty-自定义协议
- 面试题
- IO
- 网络IO模型
- 第五章 操作系统
- IO
- 文件系统的相关概念
- Java几种文件读写方式性能对比
- Socket
- 内存管理
- 进程、线程、协程
- IO模型的演化过程
- 第六章 计算机网络
- 第七章 消息队列
- RabbitMQ
- 第八章 开发框架
- Spring
- Spring事务
- Spring MVC
- Spring Boot
- Mybatis
- Mybatis-Plus
- Shiro
- 第九章 数据库
- Mysql
- Mysql中的索引
- Mysql中的锁
- 面试常见问题
- Mysql中的日志
- InnoDB存储引擎
- 事务
- Redis
- redis的数据类型
- redis数据结构
- Redis主从复制
- 哨兵模式
- 面试题
- Spring Boot整合Lettuce+Redisson实现布隆过滤器
- 集群
- Redis网络IO模型
- 第十章 设计模式
- 设计模式-七大原则
- 设计模式-单例模式
- 设计模式-备忘录模式
- 设计模式-原型模式
- 设计模式-责任链模式
- 设计模式-过滤模式
- 设计模式-观察者模式
- 设计模式-工厂方法模式
- 设计模式-抽象工厂模式
- 设计模式-代理模式
- 第十一章 后端开发常用工具、库
- Docker
- Docker安装Mysql
- 第十二章 中间件
- ZooKeeper