Supplier 的核心价值是解耦创建与使用,实现延迟加载,从而节省内存、缩短启动时间、减少无效 GC;适用于高成本对象初始化、Optional 条件默认值、轻量级单次缓存及按需注入等场景。

直接用 new 初始化对象或执行耗时计算,往往在系统启动、配置加载、甚至日常调用中造成资源浪费。Supplier 接口的核心价值,就是把“创建”和“使用”解耦——只在真正需要时才执行,从而压缩内存、缩短启动时间、减少无效 GC。
延迟加载高成本对象
当某个对象构造开销大(比如读取大文件、连接远程服务、解析复杂 JSON),不要在字段声明或构造器里直接初始化。
- 错误写法:立即加载,不管后续是否用到
private final BigConfig config = loadBigConfig(); // 启动即执行 - 正确写法:封装为 Supplier,调用
get()时才触发
private final Supplier<BigConfig> configSupplier = () -> loadBigConfig();
// 使用时才加载:configSupplier.get()
这样做的好处是:类加载、实例化阶段不占用内存和 CPU;若该配置全程未被访问,就完全跳过加载过程。
配合 Optional 实现条件性默认值
在使用 Optional 获取值时,避免滥用 orElse ——它会无条件执行默认值表达式,哪怕 Optional 本身有值。
- 风险示例:
user.orElse(new ExpensiveUser())→ 每次都 new,无论 user 是否存在 - 推荐写法:
user.orElseGet(() -> createExpensiveUser())→ 仅当 user 为空时才调用 - 更进一步:可复用已有方法引用,提升可读性
user.orElseGet(this::buildDefaultUser)
这种写法在高频接口、循环体或批量处理中效果尤为明显,实测可降低 30%~50% 的无效对象创建开销。
构建轻量级单次缓存(Memoization)
某些计算结果不变,但又不想在类初始化时就固化(比如依赖运行时环境的配置路径),可用 Supplier + volatile + 双重校验实现线程安全的懒加载缓存。
- 定义缓存容器:
private volatile String cachedPath; - 封装带缓存的 Supplier:
Supplier<String> pathSupplier = () -> {<br> if (cachedPath == null) {<br> synchronized (this) {<br> if (cachedPath == null) {<br> cachedPath = resolveRuntimePath();<br> }<br> }<br> }<br> return cachedPath;<br>};
相比每次调用都重新计算,这种方式确保只执行一次,且无需引入额外依赖(如 Guava Cache)。
按需注入与框架集成思路
Spring 的 @Lazy 注解底层逻辑就类似 Supplier:Bean 不在上下文刷新时实例化,而是在首次 getBean() 或注入点被访问时才创建。你可以模仿这个思路,在自定义工厂或策略类中传入 Supplier 而非具体实例:
- 接口设计支持延迟:
public void process(Supplier<DataProcessor> processorSupplier) {<br> DataProcessor p = processorSupplier.get(); // 真正用时才初始化<br> p.execute();<br>} - 便于单元测试:传入 mock Supplier,避免真实依赖启动
- 适配不同生命周期:同一 Supplier 可用于短生命周期请求,也可复用于长生命周期服务



















