lambda 表达式实现延迟执行,即封装逻辑、按需触发,通过函数式接口(如supplier)的get()等方法调用时才运行;它不自动缓存,每次调用均重新执行。

Lambda 表达式本身不立即执行,而是把一段逻辑“包起来”,等你调用 .get()、.apply() 或其他函数式接口定义的方法时才真正运行——这就是 Java 中最自然的延迟执行机制。
核心原理:封装逻辑,按需触发
Java 的函数式接口(如 Supplier、Function、Consumer)是 Lambda 延迟执行的载体。Lambda 只是实现了这些接口的实例,它不运行代码,只保存“将来要怎么运行”的描述。
- 写
() -> expensiveOperation(),此时 expensiveOperation() 并未调用 - 只有当你显式调用
supplier.get()时,里面的方法才会执行 - 参数在 Lambda 定义时被捕获(闭包),但执行时机完全由调用方控制
典型应用场景与写法
延迟执行不是炫技,而是解决“可能白干”的问题。常见场景有:
-
避免无效日志拼接:日志级别关闭时,字符串拼接、对象 toString() 全部跳过
logger.debug(() -> "User " + user.getId() + " accessed " + resource.getName()); -
优化 Optional 空值兜底:远程调用只在缓存缺失时触发
Optional.ofNullable(localValue).orElseGet(() -> callRemoteService()); -
懒加载高成本计算:如大数据聚合、JSON 解析、格式化等
Supplier<bigdecimal> amount = () -> parseAmount(rawText); // 不解析,直到 amount.get()</bigdecimal>
自定义延迟转换器统一管理
当多个地方需要做类似“字符串 → 对象”“ID → 实体”这类耗时转换时,可抽象为一个轻量接口:
@FunctionalInterface interface LazyConverter<t> { T convert(); }</t>
- 构造时传入上下文和逻辑:
LazyConverter<user> userLoader = () -> userService.findById(userId);</user> - 业务中按需调用:
User user = userLoader.convert();,仅此处触发查询 - 比直接调用方法更清晰地表达“这个值是可选的、代价高的”语义
注意:延迟 ≠ 自动缓存
Lambda 封装的是“每次调用都重新执行”的行为。如果想做到“只算一次、后续复用”,需要额外加一层记忆化(memoization),比如用 Thunk 包装 Supplier,或借助 Guava 的 Suppliers.memoize()。
单纯用 Lambda 实现的是“要不要执行”的开关,不是“执行几次”的控制。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











