一. 简介
Lambda 表达式是函数式编程思想的体现,强调做什么,而不是以什么方式去做。
面向对象编程思想强调的是对象,必须通过对象的形式来做一些事情。比如多线程执行任务,需要创建对象,对象需要实现指定接口,然后再执行等。过程相对繁琐。而如果使用函数式编程思想,可以直接通过传递一段代码给线程对象执行,不需要创建任务对象。
Lambda 表达式可以被视为匿名函数,允许在需要函数的地方以更简洁的方式定义功能。
因此只要是函数式接口,就可以使用 Lambda 表达式简化。
函数式接口指的是接口中有且只有一个未实现的方法。如果超过一个,则不是函数式接口;如果有一个默认实现方法,一个未实现的方法,也是函数式接口。
// 接口中有超过一个未实现方法,不是函数式接口
interface MyInterface {
int sum(int a, int b);
int min(int a, int b);
}
// 接口中只有一个未实现的方法,是函数式接口
interface MyCase{
int hello();
default int hello(int a){return a;} //默认实现
}
可以用 JDK 中提供的检查注解 @FunctionalInterface 来检查该接口是否为函数式接口。
正常情况下:
异常情况下:
二. Lambda 表达式的格式
1. 标准格式
( 参数列表 )-> { 代码 }
2. 格式说明
小括号内是参数列表,语法与传统方法参数列表一致,没有参数就留空,有多个就用逗号分隔。
箭头符号 ->,代表指向动作。
大括号内是业务逻辑代码,语法与传统方法体一致。
3. 举例
创建线程
// 传统方式
Thread thread1 = new Thread(new Runnable() {
@Override
public void run () {
System.out.println("线程需要执行的任务代码1");
}
});
thread1.start();
// Lambda表达式
Thread t2 = new Thread(()->{
System.out.println("线程需要执行的任务代码2");
});
t2.start();
比较器
List<Integer> list = new ArrayList<>();
Collections.addAll(list,11,22,33,44,55);
System.out.println("排序之前的集合:" + list);
// 传统方式
Collections.sort(list, new Comparator<Integer>() {
@Override
public int compare (Integer o1, Integer o2) {
return o2-o1;
}
});
// Lambda表达式
Collections.sort(list,(Integer o1, Integer o2)->{return o2-o1;});
System.out.println("排序之后的集合:" + list);
三. Lambda 表达式与函数式接口
假如有一个接口 MyInterface,里面有一个方法 sum(),
interface MyInterface {
int sum(int a, int b);
}
想要实现这个接口,有两种方法:
1. 自己写实现类
class MyInterfaceImpl implements MyInterface {
@Override
public int sum(int a, int b) {
return a + b;
}
}
然后调用,
public class Lambda {
public static void main(String[] args) {
MyInterface myInterface = new MyInterfaceImpl();
int result = myInterface.sum(1, 2);
System.out.println(result);
}
}
2. 创建匿名实现类
每个接口都去写对应的实现类相对麻烦,因此可以采用匿名实现类,动态的去实现接口。
public class Lambda {
public static void main(String[] args) {
// 1. 自己创建实现类对象
MyInterface myInterface = new MyInterfaceImpl();
int result = myInterface.sum(1, 2);
System.out.println("自己创建的实现类对象 " + result);
// 2. 创建匿名实现类
MyInterface myInterface1 = new MyInterface() {
@Override
public int sum(int a, int b) {
return a*a + b*b;
}
};
int result1 = myInterface1.sum(1, 2);
System.out.println("匿名实现类 " + result1);
}
}
在匿名实现类中,很多格式上的东西都是固定的,因此可以进一步简化,只保留动态的东西,比如参数、方法体内容等,
// 2. 匿名实现类
MyInterface myInterface1 = new MyInterface() {
@Override
public int sum(int a, int b) {
return a*a + b*b;
}
};
// 3. Lambda表达式实现接口 参数列表 + 箭头 + 方法体
MyInterface myInterface2 = (int a, int b) -> {
return a * a + b * b;
};
进一步思考,其实参数类型也是固定的,还可以再简化,
MyInterface myInterface3 = (x, y) -> {
return x * x + y * y;
};
参数名不一定是接口中定义的(a,b),也可以是其它名字,比如(x,y)。
此外,参数部分如果为空,可以留空,即只写一个(),但不能不写括号;或者如果只有一个参数,可以只写一个参数名,
// 入参为控
interface MyCase1{
int hello();
}
public class Lambda {
public static void main(String[] args) {
MyCase myCase1 = () -> {
return 1;
};
}
}
// 只有一个参数 a
interface MyCase2{
int hello(int a);
}
public class Lambda {
public static void main(String[] args) {
MyCase1 myCase2 = a -> {
return a + 1;
};
}
}
方法体如果只有一句话,{ } 和 return 可以省略,
interface MyCase2{
int hello(int a);
}
public class Lambda {
public static void main(String[] args) {
MyCase1 myCase2 = a -> a + 2;
// 调用方法
System.out.println(myCase2.hello(1));
}
}
四. Lambda 表达式的表现形式
1. 变量形式
变量的类型为函数式接口(不常用)
// 变量的形式
Runnable r = ()->{
System.out.println("任务代码");
};
// 函数式接口类型的变量
Thread t = new Thread(r);
2. 参数形式
方法的形参类型为函数式接口(常用)
// 变量的形式-比较器
Comparator<Integer> comparable = (o1, o2)->{return o2 - o1;};
// 创建集合
ArrayList<Integer> list = new ArrayList<>();
// 存入数据
Collections.addAll(list,11,22,33,44,55);
// 将函数式接口类型的形参类型,传给Collections
Collections.sort(list,comparable);
3. 返回值形式
方法的返回值类型为函数式接口(常用)
// 定义一个方法
public static Comparator<Integer> getComparator(){
return (Integer o1,Integer o2)->{return o2-o1;};
}
public static void main (String[] args) {
// 返回值形式
Collections.sort(list,getComparator());
}