版权声明:转载请注明原始链接 https://blog.csdn.net/sswqzx/article/details/82975338
1、概述
简介:Lambda表达式是Java SE 8中一个重要的新特性。lambda表达式允许你通过表达式来代替功能接口
格式:()->{}
():接口中抽象方法的参数列表.
-> :分隔符
{}:接口中抽象方法的实现体.
2、Lambda使用条件
使用Lambda表达式必须有接口、且接口中有且仅有一个抽象方法、
或必须有“函数式接口”作为方法的参数
函数式接口:只有一个抽象方法(Object类中的方法除外)的接口是函数式接口
3、Lambda表达式省略规则
1. 小括号内参数的类型可以省略;
2. 如果小括号内有且仅有一个参,则小括号可以省略;如果没有参数、小括号不能省
3. 如果大括号内有且仅有一个语句,则无论是否有返回值,都可以省略大括号、return关键字及语句分号。
4、Runnable接口优化
说明:Runnable接口中有且只有一个抽象方法run、所以是函数式接口、就可以使用Lambda表达式了
演示:
public class ThreadTest {
public static void main(String[] args) {
// 方案一 : 实现类
// new Thread(new MyRunnable()).start();
// 方案二 : 匿名实现类 (省略了实现类的名称)
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + " -> run ... " + i);
}
}
}).start();
// 方式三 : Lambda 表达式 (能省则省)
// 省略1 : 接口的名称.
// 省略2 : 抽象方法的名称.
// 自动推导 : Thread 类的构造方法. 推导出函数式接口的名称为 Runnable, 在根据 Runnable 函数式接口就可以推导出 `抽象方法` 的名称.
/*
1. () : 表示抽象方法 run 的参数列表.
2. -> : 分隔符. 参数列表 -> 方法体
3. {} : 抽象方法的方法体实现.
*/
new Thread(() -> {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + " -> run ... " + i);
}
}).start();
// 主线程执行代码 ...
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + " -> run ... " + i);
}
}
}
5、Comparator接口优化
说明:Comparator接口中有且仅有一个抽象方法compare、所以可以用Lambda表达式
需求 : 对集合中的 Student 对象进行排序. 规则为: 按照年龄从小到大排列.
演示:
public class StudentSortTest {
public static void main(String[] args) {
// 1. 创建一个集合, 存储多个 Student 对象
ArrayList<Student> list = new ArrayList<>();
list.add(new Student("张三", 18));
list.add(new Student("李四", 16));
list.add(new Student("王五", 19));
list.add(new Student("赵六", 17));
// 排序 : 函数式接口相关的方法. Collections.sort(list, Comparator函数式接口);
// 方式一 : 实现类
Collections.sort(list, new MyComparactor());
// 方式二 : 匿名实现类
Collections.sort(list, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
// 按照年龄从小到大
return o1.getAge() - o2.getAge();
}
});
// 方式三 : Lambda 表达式
/*
1. () : 抽象方法的参数列表
2. -> : 分隔符
3. {} : 抽象方法的实现体
*/
Collections.sort(list, (Student o1, Student o2) -> {
// 按照年龄从小到大
return o1.getAge() - o2.getAge();
});
Collections.sort(list, (o1, o2) -> { return o1.getAge() - o2.getAge(); });
Collections.sort(list, (a, b) -> a.getAge() - b.getAge());//省略后的写法
// 遍历
for (Student stu : list) {
System.out.println(stu);
}
}
}
6、Lambda无参无返回值
package com.mvcCase.Test;
public interface Cook {
public abstract int eat(int num1, int num2);
}
package com.mvcCase.Test;
public class LambdaTest {
public static void main(String[] args) {
// 调用方法, 传递 Lambda 表达式
// 请问 : 如果一个方法是接口类型, 那么其真正需要的是该接口的实现类对象.
// 方式一 : 匿名实现类传递参数
keepAlive(new Cook() {
// 方法的定义 :
@Override
public void eat() {
System.out.println("吃饭、匿名实现类");
}
});
// 方式二 : Lambda 表达式
keepAlive(() -> { System.out.println("吃饭、Lambda");});
// 方式三 : 省略原则
keepAlive(() -> System.out.println("吃饭、Lambda简写"));
}
// 方法 : 必须使用 `函数式接口` 作为方法的参数类型
public static void keepAlive(Cook cook) {
// 接口调用抽象方法, 其真正调用的是 `实现类` 的重写方法.
cook.eat(); // 方法的调用
}
}
7、Lambda有参有返回值
package com.mvcCase.Test;
public interface Cook {
public abstract int eat(int num1, int num2);
}
package com.mvcCase.Test;
public class LambdaTest {
public static void main(String[] args) {
// 调用方法, 传递 Lambda 表达式
// 请问 : 如果一个方法是接口类型, 那么其真正需要的是该接口的实现类对象.
// 方式一 : 匿名实现类传递参数
int sum = keepAlive(10, 10, new Cook() {
// 方法的定义 :
@Override
public int eat(int num1, int num2) {
return num1 + num2;
}
});
System.out.println("总共多少次=" + sum);
// 方式二 : Lambda 表达式
int sum1 = keepAlive(20, 20, (n1, n2) -> { return n1 + n2; });
System.out.println("总共多少次=" + sum1);
// 方式三 : 省略原则
int sum2 = keepAlive(30,30,(a1, a2)->a1+a2);
System.out.println("总共多少次=" + sum2);
}
// 方法 : 必须使用 `函数式接口` 作为方法的参数类型
public static int keepAlive(int num1, int num2, Cook cook) {
// 接口调用抽象方法, 其真正调用的是 `实现类` 的重写方法.
return cook.eat(num1, num2); // 方法的调用
}
}