lambda表达式仅适用于函数式接口(有且仅一个抽象方法),如runnable、comparator;非函数式接口(如windowadapter)不可用。它简化匿名内部类,省略模板代码,聚焦“参数→动作”,支持参数和体的灵活省略,但需遵守“事实final”变量限制,复杂逻辑应优先使用命名方法。

Lambda 表达式不是“所有匿名内部类的通用替身”,而是专为函数式接口设计的语法糖——它只在接口有且仅有一个抽象方法时生效。理解这一点,是避免编译错误和误用的关键。
核心前提:必须是函数式接口
函数式接口指只有一个抽象方法的接口(可以有默认方法、静态方法或重写 Object 的方法)。Java 用 @FunctionalInterface 注解来标识并强制校验。例如:
-
Runnable:只有run() -
ActionListener:只有actionPerformed() -
Comparator:只有compare() -
WindowAdapter不行——它有 7 个抽象方法,不能用 Lambda 替代
简化逻辑:去掉模板,聚焦行为
匿名内部类本质是“定义一个一次性类 + 实例化”,而 Lambda 直接表达“我要执行什么”。对比来看:
传统写法:
new Thread(new Runnable() {public void run() {
System.out.println("Hello");
}
});
Lambda 写法:
new Thread(() -> System.out.println("Hello"));省去了:类名、方法声明、return 关键字(无返回值时)、new 和大括号嵌套,只保留“参数 → 动作”这一核心关系。
参数与体的灵活省略规则
Lambda 支持按需精简,IDE 通常能自动推导类型:
- 无参:用
(),如() -> doSomething() - 单参:可省括号,如
e -> handle(e)或(ActionEvent e) -> handle(e) - 单句表达式:省大括号和分号,如
(a, b) -> a.compareTo(b) - 多句逻辑:必须用大括号 + 分号,如
(x, y) -> { log(x); return x + y; }
注意捕获变量的“事实 final”限制
Lambda 只能访问未被重新赋值的局部变量(即“事实 final”),因为 JVM 实际捕获的是变量值的副本,而非引用。例如:
int count = 0;list.forEach(x -> count++); // 编译报错
若需修改外部状态,推荐方式是:
- 改用原子类:
AtomicInteger count = new AtomicInteger(); list.forEach(x -> count.incrementAndGet()); - 或换思路:用
stream().reduce()等无副作用操作替代
不是越短越好:该用还是该写命名方法?
简洁不等于合适。以下情况建议放弃 Lambda:
- 逻辑超过 3 行,或含 if/else、try/catch 等复杂控制流
- 需要复用、打条件断点、加日志追踪调试
- 性能敏感场景(如高频创建短生命周期对象),Lambda 可能带来额外 invokedynamic 开销
此时更清晰的做法是:写一个私有方法,再用方法引用,如 list.forEach(this::processItem)。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











