Supplier接口是实现懒加载最轻量自然的方式:不接收参数、只返回值,调用get()时才执行逻辑;适用于包装耗时操作、配合Optional/Stream延迟求值,并需注意其非幂等性及避免副作用。

Supplier 接口是实现懒加载最轻量、最自然的方式之一:它不接收参数、只返回一个值,且只有在调用 get() 时才真正执行逻辑,天然契合“用时才算”的懒加载语义。
用 Supplier 包装耗时操作
把创建开销大、依赖外部资源(如数据库查询、HTTP 请求、文件读取)或计算密集型的对象封装进 Supplier,避免初始化时就执行。
- 例如,不直接 new 一个需要远程调用的配置对象,而是写成:
Supplier<Config> configSupplier = () -> fetchConfigFromRemote(); - 此时
configSupplier本身几乎无成本;只有后续某处调用configSupplier.get()才触发真实获取。
结合 Optional 或字段做延迟初始化
在类中用 Supplier 配合私有字段 + 懒检查,实现线程安全(或非安全)的按需加载。
- 简单场景(单线程/已保证调用顺序):
private Supplier<List<User>> usersSupplier = () -> userDao.findAll();
private List<User> users;
public List<User> getUsers() {
if (users == null) users = usersSupplier.get();
return users;
} - 注意:这种写法不是线程安全的;若需并发安全,可用
AtomicReference或双重检查锁,但更推荐直接用 Supplier + 明确调用时机,而非隐藏在 getter 中。
配合 Stream 或 Optional 延迟求值
Supplier 可无缝融入函数式链路,让整个数据流保持惰性。
立即学习“Java免费学习笔记(深入)”;
- 比如构造一个可能为空的 Supplier,并用于 Optional 的 orElseGet:
Optional<String> cached = cache.get("key");
String result = cached.orElseGet(() -> computeExpensiveValue());
这里computeExpensiveValue()仅在缓存未命中时执行。 - 再如 Stream 处理中延迟生成默认值:
stream.map(item -> item.getValue()).orElseGet(() -> fallbackSupplier.get())
避免常见误区
Supplier 是函数式接口,设计初衷是“一次性的值提供者”,不是状态管理工具。
- 不要反复调用同一个 Supplier 实例期望返回相同结果——除非内部逻辑本身是幂等的(如返回常量、或封装了缓存)。否则每次
get()都会重新执行。 - 若需要“首次调用后缓存结果”,应显式包装,例如用
LazyVal工具类,或借助 Guava 的Suppliers.memoize():
Supplier<Data> lazyData = Suppliers.memoize(() -> loadFromDB()); - 不要在 Supplier 里做副作用操作(如修改共享变量、发通知),除非你明确控制调用时机和次数。


















