Lambda表达式
字数: 0 字 时长: 0 分钟
1. 概述
Lambda 表达式是 JDK 8 引入的一种语法,可以简化函数式接口匿名内部类的写法。
它是函数式编程思想的重要体现,让我们不再过多关注“创建了什么对象”,而是更关注:
传入什么参数,以及对这些参数执行什么操作。
例如,原本需要通过匿名内部类实现接口:
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Hello");
}
}).start();使用 Lambda 表达式后:
new Thread(() -> System.out.println("Hello")).start();不是所有匿名内部类都可以使用 Lambda,只有函数式接口才能使用 Lambda 表达式。
函数式接口指只有一个抽象方法的接口。
2. 核心原则
Lambda 表达式最重要的原则:
可推导,可省略。
如果某些信息可以通过上下文推导出来,就可以省略不写。
例如:
- 参数类型可以推导,可以省略
- 方法名可以通过函数式接口的抽象方法推导,因此不需要写
- 只有一个参数时,小括号可以省略
- 方法体只有一条语句时,大括号可以省略
- 方法体只有一条
return语句时,return和分号可以一起省略
Lambda 最终主要关注两部分:
参数
↓
执行逻辑3. 基本格式
Lambda 表达式的基本格式:
(参数列表) -> {
代码
}其中:
(参数列表) -> {方法体}
↑ ↑
参数 执行逻辑3.1 练习一:Runnable
原来的匿名内部类写法:
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("我是老写法");
}
}).start();Runnable 是一个函数式接口,其中只有一个抽象方法:
void run();因此真正需要关注的只有方法的参数和方法体。
run() 没有参数,因此可以理解为:
() -> {
System.out.println("我是新写法");
}最终简化为:
new Thread(() -> {
System.out.println("我是新写法");
}).start();如果方法体只有一句代码,还可以继续简化:
new Thread(() -> System.out.println("我是新写法")).start();3.2 练习二:IntBinaryOperator
现有方法如下,其中 IntBinaryOperator 是一个函数式接口:
public static int calculateNum(IntBinaryOperator operator) {
int a = 10;
int b = 20;
return operator.applyAsInt(a, b);
}使用匿名内部类:
public static void main(String[] args) {
calculateNum(new IntBinaryOperator() {
@Override
public int applyAsInt(int left, int right) {
return left + right;
}
});
}对于 Lambda 来说,我们主要关注:
(int left, int right) -> {
return left + right;
}因此可以改造成:
calculateNum((int left, int right) -> {
return left + right;
});继续按照省略规则,可以写成:
calculateNum((left, right) -> left + right);3.3 练习三:IntPredicate
现有方法如下,其中 IntPredicate 是一个函数式接口:
public static void printNum(IntPredicate predicate) {
int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (int i : arr) {
if (predicate.test(i)) {
System.out.println(i);
}
}
}使用匿名内部类:
public static void main(String[] args) {
printNum(new IntPredicate() {
@Override
public boolean test(int value) {
return value % 2 == 0;
}
});
}改造成 Lambda:
printNum((int value) -> {
return value % 2 == 0;
});继续简化:
printNum(value -> value % 2 == 0);3.4 练习四:Function
定义一个类型转换方法:
public static <R> R typeConver(Function<String, R> function) {
String str = "1235";
return function.apply(str);
}使用匿名内部类,将 String 转换为 Integer:
public static void main(String[] args) {
Integer integer = typeConver(new Function<String, Integer>() {
@Override
public Integer apply(String s) {
return Integer.valueOf(s);
}
});
System.out.println(integer);
}使用 Lambda:
Integer integer = typeConver((String s) -> {
return Integer.valueOf(s);
});继续简化:
Integer integer = typeConver(s -> Integer.valueOf(s));也可以将字符串转换成另一个字符串。
匿名内部类:
String str = typeConver(new Function<String, String>() {
@Override
public String apply(String s) {
return s + "哈哈";
}
});
System.out.println(str);Lambda:
String str = typeConver((String s) -> {
return s + "哈哈";
});继续简化:
String str = typeConver(s -> s + "哈哈");3.5 练习五:IntConsumer
定义数组遍历方法,其中 IntConsumer 是一个函数式接口:
public static void foreachArr(IntConsumer consumer) {
int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (int i : arr) {
consumer.accept(i);
}
}使用匿名内部类:
public static void main(String[] args) {
foreachArr(new IntConsumer() {
@Override
public void accept(int value) {
System.out.println(value);
}
});
}改造成 Lambda:
foreachArr((int value) -> {
System.out.println(value);
});继续简化:
foreachArr(value -> System.out.println(value));4. 省略规则
4.1 参数类型可以省略
原写法:
foreachArr((int value) -> {
System.out.println(value);
});参数类型可以根据 IntConsumer 推导,因此可以省略:
foreachArr((value) -> {
System.out.println(value);
});4.2 单个参数的小括号可以省略
当 Lambda 只有一个参数时:
foreachArr((value) -> {
System.out.println(value);
});可以省略小括号:
foreachArr(value -> {
System.out.println(value);
});没有参数或者有多个参数时,小括号不能省略。
4.3 方法体只有一句代码时可以省略大括号
原写法:
foreachArr(value -> {
System.out.println(value);
});可以简化为:
foreachArr(value -> System.out.println(value));4.4 单条 return 语句可以继续省略
例如:
calculateNum((left, right) -> {
return left + right;
});如果方法体只有一条 return 语句,可以同时省略大括号、return 和分号:
calculateNum((left, right) -> left + right);注意:
(left, right) -> {
return left + right;
}不能只删除 return:
// 错误
(left, right) -> {
left + right;
}而是需要一起简化:
(left, right) -> left + right5. 小结
Lambda 表达式的核心并不复杂:
匿名内部类
↓
找到唯一的抽象方法
↓
保留参数 + 方法体
↓
使用 -> 连接
↓
根据“可推导可省略”继续简化最核心的一句话:
Lambda 主要关注参数和方法体,可推导出来的内容就可以省略。