supplier 是 java 8 中用于惰性求值的无参函数式接口,仅在调用 get() 时执行逻辑;常用于 orelseget、stream 短路操作及自定义懒加载,实现按需计算与资源延迟初始化。

Supplier 接口是 Java 8 函数式编程中实现惰性求值最直接、最常用的工具之一。它的核心价值不在于“做了什么”,而在于“什么时候做”——只在真正需要时才执行计算,跳过所有冗余开销。
Supplier 是什么,为什么它能延迟执行
Supplierpublic interface Supplier<t> { T get(); }</t>。它本身不触发任何逻辑,只是把一段创建对象或执行操作的代码“包起来”,等到调用 get() 方法时才真正运行。
- 不传参、不依赖外部状态,天然适合封装“按需生成”的逻辑
- 编译器和 JVM 不会提前执行 get(),所以整个 Supplier 实例可以安全地传递、缓存、条件调用
- 与方法引用(如
this::createUser)或 Lambda(如() -> new ExpensiveObject())结合后,语义清晰且零额外对象开销
在 Optional 中用 orElseGet 替代 orElse
这是 Supplier 惰性求值最典型、最容易被忽略的实战场景。二者表面相似,行为却截然不同:
-
orElse("default"):字符串字面量立即加载,没问题;但换成
orElse(new HeavyObject()),每次调用都会实例化,不管 Optional 是否有值 - orElseGet(() -> new HeavyObject()):Lambda 被包装成 Supplier,仅当 Optional 为空时才调用 get(),HeavyObject 的构造逻辑被真正推迟
例如缓存查询失败后回源数据库:
User user = Optional.ofNullable(cache.get(id))
.orElseGet(() -> db.loadUser(id)); // loadUser 只在缓存未命中时执行
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
在 Stream 中配合中间操作控制执行节奏
Stream 的惰性本质依赖 Supplier 的延迟能力——虽然不直接暴露 Supplier 参数,但很多终止操作(如 findFirst、anyMatch)会触发短路,让 map/filter 等中间操作也只处理必要元素。
- 写
stream().map(x -> expensiveTransform(x))本身不执行,直到遇到 collect/findAny 等终止操作 - 若用
findFirst(),可能只对前几个元素调用expensiveTransform,其余全部跳过 - 这背后是 Stream 内部将每个中间操作封装为延迟可执行单元,其调度逻辑与 Supplier 的“按需取值”思想一致
自定义延迟初始化工具类
你可以用 Supplier 封装高成本资源,实现线程安全的懒加载,比双重检查锁更简洁:
public class LazyValue
private final Supplier
private volatile T value;
private volatile boolean initialized;
public LazyValue(Supplier
this.supplier = supplier;
}
public T get() {
if (!initialized) {
synchronized (this) {
if (!initialized) {
value = supplier.get(); // 关键:只在这里执行
initialized = true;
}
}
}
return value;
}
}
使用时只需传入 Supplier:LazyValue<connection> conn = new LazyValue(() -> DriverManager.getConnection(url));</connection>,连接创建被严格限制在第一次 get() 调用。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










