一、Lambda 表达式概述
Lambda 表达式是 Java 8 引入的核心特性,本质是匿名函数 (无名称的方法),用于简化函数式接口(仅含一个抽象方法的接口)的实现,让代码更简洁、支持函数式编程风格。
核心优势
- 代码简洁 :消除匿名内部类的冗余代码(如
new、@Override)。 - 函数作为参数:可将代码块作为方法参数传递,灵活处理数据流(如 Stream API)。
- 性能优化 :避免为每个匿名内部类生成独立
.class文件,减少内存开销。
二、函数式接口(Lambda 的基石)
Lambda 表达式必须依赖函数式接口 ,即有且仅有一个抽象方法的接口。
1. 定义与注解
- 用
@FunctionalInterface注解标记(非强制,编译校验)。 - 接口中只能有一个抽象方法,可包含默认方法、静态方法。
java
// 自定义函数式接口
@FunctionalInterface
interface Calculator {
int compute(int a, int b); // 唯一抽象方法
}
2. JDK 内置四大核心函数式接口(java.util.function包)
表格
| 接口 | 抽象方法 | 用途 |
|---|---|---|
Consumer<T> |
void accept(T t) |
消费型:接收参数,无返回值 |
Supplier<T> |
T get() |
供给型:无参数,返回数据 |
Predicate<T> |
boolean test(T t) |
断言型:判断条件,返回布尔值 |
Function<T,R> |
R apply(T t) |
函数型:接收参数,返回结果 |
三、Lambda 表达式语法
1. 基本结构
java
运行
java
(参数列表) -> { 方法体 }
- 参数列表:对应函数式接口抽象方法的参数,类型可省略(编译器自动推断)。
- ->:Lambda 操作符,分隔参数与方法体。
- 方法体 :实现逻辑,单行可省略
{}与return,多行必须包裹{}并显式return。
2. 语法简化规则(必背)
表格
| 场景 | 示例 | 说明 |
|---|---|---|
| 无参数 | () -> System.out.println("Hello") |
必须写空括号 |
| 单个参数 | x -> x * 2 |
可省略括号与参数类型 |
| 多个参数 | (a, b) -> a + b |
不可省略括号,类型可省略 |
| 单行方法体 | (a, b) -> a + b |
省略{}、return、分号 |
| 多行方法体 | x -> { int r = x * 2; return r; } |
必须加{},有返回值需return |
| 显式类型 | (int a, int b) -> a + b |
手动声明参数类型(可选) |
四、基础示例
1. 无参数无返回值(Runnable)
java
// 传统匿名内部类
Runnable runnable1 = new Runnable() {
@Override
public void run() {
System.out.println("Hello Lambda");
}
};
// Lambda 简化
Runnable runnable2 = () -> System.out.println("Hello Lambda");
runnable2.run(); // 输出:Hello Lambda
2. 单个参数无返回值(Consumer)
java
// 传统写法
Consumer<String> consumer1 = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
// Lambda 简化
Consumer<String> consumer2 = s -> System.out.println(s);
consumer2.accept("Hello Consumer"); // 输出:Hello Consumer
3. 多个参数有返回值(自定义接口)
java
// 自定义函数式接口
@FunctionalInterface
interface MathOp {
int calculate(int a, int b);
}
// Lambda 实现
MathOp add = (a, b) -> a + b;
MathOp multiply = (a, b) -> a * b;
System.out.println(add.calculate(3, 5)); // 输出:8
System.out.println(multiply.calculate(3, 5)); // 输出:15
4. 断言型接口(Predicate)
java
// 判断字符串是否为空
Predicate<String> isEmpty = s -> s == null || s.trim().isEmpty();
System.out.println(isEmpty.test("")); // 输出:true
System.out.println(isEmpty.test("Java")); // 输出:false
5. 函数型接口(Function)
java
// 字符串转整数
Function<String, Integer> strToInt = s -> Integer.parseInt(s);
System.out.println(strToInt.apply("123")); // 输出:123
五、Lambda 变量作用域
1. 访问外部变量
Lambda 可访问 ** 外部 final 或 effectively final(无二次赋值)** 的局部变量、成员变量、静态变量。
java
int num = 10; // effectively final(未二次赋值)
Runnable runnable = () -> System.out.println(num); // 合法
runnable.run(); // 输出:10
2. 禁止修改外部变量
Lambda 内部不能修改外部局部变量(编译报错)。
int count = 0;
Runnable runnable = () -> {
count++; // 编译错误:Lambda 内部不能修改外部局部变量
};
3. 访问成员变量与静态变量
public class LambdaDemo {
private String msg = "Hello"; // 成员变量
private static String staticMsg = "Static Hello"; // 静态变量
public void test() {
Runnable runnable = () -> {
System.out.println(msg); // 访问成员变量
System.out.println(staticMsg); // 访问静态变量
};
runnable.run();
}
}
六、方法引用(Lambda 进阶简化)
方法引用是 Lambda 的简写形式 ,通过::符号直接引用已有方法(静态方法、实例方法、构造方法),进一步简化代码。
1. 静态方法引用:类名::静态方法
// Lambda 写法
Function<String, Integer> strToInt1 = s -> Integer.parseInt(s);
// 方法引用
Function<String, Integer> strToInt2 = Integer::parseInt;
2. 实例方法引用:对象::实例方法
String str = "Hello";
// Lambda 写法
Supplier<Integer> length1 = () -> str.length();
// 方法引用
Supplier<Integer> length2 = str::length;
3. 构造方法引用:类名::new
// Lambda 写法
Supplier<List<String>> listSupplier1 = () -> new ArrayList<>();
// 方法引用
Supplier<List<String>> listSupplier2 = ArrayList::new;
七、Lambda 与 Stream API 结合(核心应用场景)
Stream API 是 Java 8 处理集合数据的工具,大量依赖 Lambda 表达式实现过滤、映射、遍历等操作。
示例:集合过滤、转换、遍历
List<String> list = Arrays.asList("Java", "Python", "C++", "JavaScript");
// 1. 过滤(Predicate):筛选以 "J" 开头的字符串
// 2. 转换(Function):转小写
// 3. 遍历(Consumer):打印结果
list.stream()
.filter(s -> s.startsWith("J"))
.map(s -> s.toLowerCase())
.forEach(s -> System.out.println(s));
// 输出:java、javascript
八、Lambda 与匿名内部类对比
表格
| 对比维度 | 匿名内部类 | Lambda 表达式 |
|---|---|---|
| 本质 | 真实类对象,生成独立.class文件 |
无类结构,JVM 动态生成,轻量级 |
| 使用范围 | 可继承类、实现任意接口 | 仅支持函数式接口 |
| 变量访问 | 可访问外部 final 变量,可修改成员变量 | 仅访问 final/effectively final 变量 |
this含义 |
指向匿名内部类自身 | 指向外部类对象 |
| 代码简洁度 | 冗余(需重写方法) | 极简(省略模板代码) |
九、注意事项与常见问题
- 必须依赖函数式接口:Lambda 不能独立使用,必须实现函数式接口。
- 参数类型推断:编译器可自动推断参数类型,无需手动声明(特殊场景除外)。
- 多行方法体需
{}与return:单行可省略,多行必须规范书写。 - 变量作用域限制:不能修改外部局部变量,仅访问 final/effectively final 变量。
- 空指针风险:Lambda 中使用外部对象时,需判空避免空指针。
十、总结
Lambda 表达式是 Java 8 函数式编程的核心,通过简洁语法简化函数式接口实现,结合 Stream API 可高效处理集合数据,大幅提升代码简洁性与可读性。掌握 Lambda 需重点理解函数式接口、语法简化规则、变量作用域、方法引用四大核心点。