一、Lambda 表达式概述
1. 定义与作用
- Lambda 表达式是 Java 8 引入的新特性,是一种简洁的匿名函数书写方式,用于简化函数式接口的实现。
- 作用:避免编写冗余的匿名内部类代码,提高代码简洁性和可读性,尤其适用于集合遍历、排序、线程任务等场景。
2. 语法结构
(参数列表) -> { 方法体 }
- 参数列表:接口抽象方法的参数,可省略类型(由编译器推断),若只有一个参数可省略括号。
- ->:Lambda 操作符,读作 “goes to”。
- 方法体:若只有一条语句,可省略大括号和分号;若有返回值,可省略
return
关键字。
二、函数式接口(Functional Interface)
1. 定义
- 指仅包含一个抽象方法的接口(允许包含默认方法、静态方法和
Object
的公共方法)。 - 必须使用
@FunctionalInterface
注解(非强制,但建议添加,用于编译器校验)。
2. 核心函数式接口
Java 8 在 java.util.function
包中提供了大量常用函数式接口,按参数和返回值分类如下:
(1)无参数无返回值:Runnable
// 传统匿名内部类
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Hello Runnable");
}
}).start();
// Lambda 表达式
new Thread(() -> System.out.println("Hello Lambda")).start();
(2)单参数无返回值:Consumer<T>
- 消费型接口,对参数进行处理(无返回值)。
Consumer<String> print = str -> System.out.println("Input: " + str);
print.accept("Lambda"); // 输出:Input: Lambda
(3)单参数有返回值:Function<T, R>
- 函数型接口,将输入参数转换为另一种类型的结果。
Function<Integer, String> convert = num -> "Number: " + num;
String result = convert.apply(123); // 输出:Number: 123
(4)布尔型单参数:Predicate<T>
- 断言型接口,用于条件判断,返回
boolean
。
Predicate<Integer> isEven = num -> num % 2 == 0;
System.out.println(isEven.test(4)); // 输出:true
(5)无参数有返回值:Supplier<T>
- 供给型接口,用于生成指定类型的数据。
Supplier<Double> randomNum = () -> Math.random();
System.out.println(randomNum.get()); // 输出随机小数(如 0.345...)
三、Lambda 表达式的使用场景
1. 集合遍历(forEach
)
List<String> list = Arrays.asList("Apple", "Banana", "Cherry");
// 传统循环
for (String item : list) {
System.out.print(item + " ");
}
// Lambda + forEach
list.forEach(item -> System.out.print(item + " ")); // 输出:Apple Banana Cherry
2. 集合排序(sort
)
List<Integer> nums = Arrays.asList(3, 1, 4, 2);
// 传统 Comparator
nums.sort(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1; // 降序
}
});
// Lambda
nums.sort((a, b) -> b - a); // 等价于上述代码
3. 多线程任务(Runnable
)
// 传统方式
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Thread running");
}
}).start();
// Lambda
new Thread(() -> System.out.println("Thread running")).start();
四、Lambda 表达式的变量捕获规则
1. 捕获外部变量
- Lambda 表达式中可访问外层作用域的变量(包括成员变量和局部变量)。
- 对局部变量的要求:必须是事实不可变的(effectively final),即变量声明后不再修改。
int num = 10; // 未修改,符合规则
Consumer<String> consumer = str -> System.out.println(str + num); // 合法
num = 20; // 报错:Cannot assign a value to final variable 'num'
2. 与匿名内部类的区别
- 匿名内部类:可修改外部局部变量(需声明为
final
)。 - Lambda 表达式:不允许修改外部局部变量,强制要求变量事实不可变,避免线程安全问题。
五、方法引用(Method Reference)
1. 定义
- 是 Lambda 表达式的简化形式,用于引用已有的方法来替代 Lambda 体中的逻辑。
- 语法:
类名::方法名
或对象::方法名
。
2. 常见类型
(1)静态方法引用(类名::静态方法
)
// Lambda:参数传递给静态方法
Function<Integer, String> func = num -> String.valueOf(num);
// 方法引用
Function<Integer, String> funcRef = String::valueOf;
(2)实例方法引用(对象::实例方法
)
String str = "Hello";
// Lambda:调用 str 的实例方法
Supplier<Integer> length = () -> str.length();
// 方法引用
Supplier<Integer> lengthRef = str::length;
(3)构造方法引用(类名::new
)
// Lambda:创建对象
Supplier<ArrayList> supplier = () -> new ArrayList();
// 方法引用
Supplier<ArrayList> supplierRef = ArrayList::new;
六、Lambda 表达式的优缺点
1. 优点
- 代码简洁:减少冗余的样板代码,提升开发效率。
- 函数式编程支持:便于使用集合流式操作(
Stream API
)和并行处理。 - 可读性增强:逻辑聚焦,代码结构更清晰。
2. 缺点
- 调试困难:无具体方法名,堆栈跟踪信息不友好。
- 学习成本:对新手而言,函数式编程思想需要适应。
- 滥用风险:过度使用可能导致代码逻辑晦涩难懂。
七、总结
- Lambda 表达式是 Java 函数式编程的核心特性,通过简化函数式接口的实现,让代码更简洁优雅。
- 函数式接口是 Lambda 表达式的载体,需牢记
@FunctionalInterface
注解的作用及常用接口(如Runnable
、Consumer
、Function
等)。 - 方法引用是 Lambda 的进阶用法,进一步提升代码的简洁性和复用性。
合理运用 Lambda 表达式,能显著提升 Java 代码的表现力和开发效率,尤其在集合操作、多线程和流式处理中优势明显。