Lambda 表达式,也可以称为闭包,它是推动 Java8 发布的最终要的新特性,允许吧函数作为又给方法的参数(函数作为参数传递进方法中)。使用 Lambda 表达式可以是代码变的更加简洁紧凑。
具体分析
1. 需求分析
创建一个新的线程,指定线程要执行的任务
public static void main(String[] args) {
// 开启一个线程
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("新线程中执行的代码:"+Thread.currentThread().getName());
}
}).start();
System.out.println("主线程中的代码:"+Thread.currentThread().getName());
}
代码分析:
- Thread 类需要一个 Runnable 接口作为参数,其中的抽象方法 run 方法是来指定线程任务内容的核心
- 为了指定 run 方法体,不得不需要 Runnable 的实现类
- 为了省去定义一个 Runnable 的实现类,不得不使用匿名内部类
- 必须覆盖重写抽象的 run 方法,所有的方法名称,方法参数,方法返回值不得不都再重写一遍,而且不能出错。
- 而实际上,我们只在乎方法体中的代码
2. lambda 初体验
Lambda 表达式是一个匿名函数,可以理解为一段可以传递的代码
new Thread(() -> {
System.out.println("新线程Lambda表达式》》》》》"+Thread.currentThread().getName());
}).start();
Lambda 表达式的优点:简化了匿名内部类的使用,语法更加简单。
匿名内部类语法冗余,体验了 Lambda 表达式后,发现 Lambda 表达式是简化匿名内部类的一种方式。
3. Lambda 的语法规则
Lambda 省去了面向对象的条条框框,Lambda 的标准格式由 3 个部门组成
(参数类型 参数名称) ->{
代码体;
}
格式说明:
- (参数类型 参数名称):参数列表
- {代码体}:方法体
- ->:箭头,分割参数列表和方法体
3.1 Lambda 练习1
练习无返回值的 Lambda
定义一个接口
public interface UserService {
void show();
}
然后创建主方法使用
public class Demo02Lambda {
public static void main(String[] args) {
goShow(new UserService() {
@Override
public void show() {
System.out.println("goShow 执行了。。。。。。");
}
});
System.out.println("======================");
goShow(() -> {
System.out.println("Lambda Show 执行了。。。。");
});
}
public static void goShow(UserService userService){
userService.show();
}
}
输出:
goShow 执行了。。。。。。
======================
Lambda Show 执行了。。。。
3.2 Lambda 练习2
练习有返回值的 Lambda
定义一个实体类
private String name;
private Integer age;
private Integer height;
然后我们在 List 集合中保存多个 Person 对象,这些对象根据 age 排序操作
public static void main(String[] args) {
List<Person> list = new ArrayList<>();
list.add(new Person("周杰伦",33,182));
list.add(new Person("刘德华",20,155));
list.add(new Person("周星驰",35,188));
list.add(new Person("国富层",23,175));
Collections.sort(list, new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
return o1.getAge()-o2.getAge();
}
});
for (Person person : list) {
System.out.println(person);
}
}
发现在 sort 方法的第二个参数是一个 Comparator 接口的匿名内部类,且执行的方法有参数和返回值,将其改写为 Lambda 表达式
System.out.println("=========================");
Collections.sort(list, (Person p1, Person p2) -> {
return p1.getAge() - p2.getAge();
});
for (Person person : list) {
System.out.println(person);
}
输出结果
Person{name='刘德华', age=20, height=155}
Person{name='国富层', age=23, height=175}
Person{name='周杰伦', age=33, height=182}
Person{name='周星驰', age=35, height=188}
4. @FunctionAlInterface
/**
这是一个标志注解,被该注解修饰的接口只能声明一个抽象方法
*/
@FunctionAlInterface
public interface UserService {
void show();
}
5. Lambda 表达式的省略写法
在 lambda 表达式的标准写法基础上,可以使用省略写法的规则为:
- 小括号内的参数类型可以省略
- 如果小括号内有且仅有一个参数,则小括号可以省略
- 如果大括号内有且仅有一个语句,可以同时省略大括号,return 关键字及语句分号。
public static void main(String[] args) {
// Lambda 省略写法
goStudent((name, age) -> name + age + " 666 ....");
goOrder(age -> 35);
}
public static void goStudent(StudentService studentService){
studentService.show("张三", 23);
}
public static void goOrder(OrderService orderService){
orderService.show(25);
}
6. Lambda 使用前提
Lambda 语法非常简洁,但是 Lambda 表达式不是随便使用的,使用时有几个特别要注意的
- 方法的参数或局部变量必须为接口才能使用 Lambda
- 接口中有且仅有一个抽象方法
7. Lambda 和匿名内部类的对比
Lambda 和匿名内部类的对比
-
所需类型不一样
- 匿名内部类的类型可以是类,抽象类,接口
- Lambda 表达式需要的类型必须是接口
-
抽象方法的数量不一样
- 匿名内部类所需的接口中的抽象方法的数量是随意的
- Lambda 表达式所需的接口中只能有一个抽象方法
-
实现原理不一样
- 匿名内部类是在编译后形成 class
- Lambda 是在程序运行的时候动态生成 class
以上就是 Lambda 的主要知识点,一开始学习的时候可能会用这不上手,但是用多了,就会感觉真香!