lambda表达式实现命令模式的核心是用函数式接口替代command接口,将行为直接封装为可传递、可复用的逻辑,无需定义命令类或匿名内部类,不生成额外.class文件,通过闭包捕获上下文并配合map实现运行时动态调度。

Java 中 Lambda 表达式实现命令模式,核心在于用函数式接口替代传统 Command 接口,把“要执行什么”直接写成一段可传递、可复用的逻辑,完全跳过定义命令类、实现类、匿名内部类这些步骤——不生成额外 .class 文件,也不需要编译期产出 $1.class。
用标准函数式接口代替 Command 接口
传统命令模式要先定义接口:
public interface Command { void execute(); }
再写一堆实现类(如 SaveCommand、OpenCommand),每个都对应一个 .class 文件。
Lambda 直接用 Runnable、Consumer<t></t>、Supplier<r></r> 等 JDK 内置接口,例如:
- 无参无返回:`() -> service.save()`
- 带参数:`user -> notification.send(user.getEmail())`
- 带返回值:`(id, name) -> userDao.update(id, name)`
这些表达式在编译后只生成主类里的私有静态方法(如 lambda$main$0),字节码中靠 invokedynamic 指令动态链接,不落地为独立 class 文件。
把行为当参数传,而不是建类去封装
调用方不再 new 命令对象,而是把逻辑直接“塞进去”:
- 原来:
remote.setCommand(new LightOnCommand(livingRoomLight)); - 现在:
remote.setCommand(() -> livingRoomLight.on());
接收者(如 livingRoomLight)被闭包捕获,Lambda 体里直接调用其方法。整个过程没新类、没 new 实例、没 import 额外类型,解耦干净,也避免了类爆炸。
配合 Map 管理命名命令,运行时动态调度
用 Map<string runnable></string> 或 Map<string consumer>></string> 存储行为,键是操作名,值是 Lambda:
commands.put("backup", () -> backupService.run());commands.put("validate", data -> validator.check(data));
执行时按名取值、直接 .run() 或 .accept(...),无需反射加载类、也不依赖类路径。所有逻辑都在内存中以函数对象存在,JVM 运行时决定怎么调用。
注意闭包与实例复用的边界
Lambda 是否复用,取决于是否捕获变量:
- 纯函数(无捕获):`() -> System.out.println("OK")`,JVM 可能复用同一实例
- 带捕获:`(user) -> mailService.send(user)`,每次调用都生成新函数对象,但仍是轻量级对象,不产生新 class 文件
即使多次创建,也只在堆上分配对象,不会触发类加载或磁盘写入 .class ——这和匿名内部类每次编译都固定产出 $1.class 有本质区别。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











