Optional:orElse 和 orElseGet 的底层逻辑,决定了它们的本质区别
在 Java 的函数式编程中,Optional<T>
是我们规避空指针的一大利器。而 orElse
和 orElseGet
是两个最常见的“备胎方法”。
它们都能在 Optional 为空时提供默认值,但底层逻辑却大相径庭。
🧠 一句话总结
方法 | 工作方式 | 特点 | 使用建议 |
---|---|---|---|
orElse | 立即执行 | 无论是否需要备胎,都会执行备胎代码 | 轻量级默认值 |
orElseGet | 延迟执行 | 只有在 Optional 为空时,才执行备胎代码 | 重成本操作,比如查库、调接口等 |
🎯 通俗类比
方法名 | 类比 | 描述 |
---|---|---|
orElse | 上来就干活 | 备胎一上车就热车,即使没用上 |
orElseGet | 按需上岗 | 真空才启动备胎,否则不吭声 |
🔍 底层机制对比
✅ orElse(T other)
public T orElse(T other) {return value != null ? value : other;
}
🔥 无论
value
是不是 null,other
会先求值!
✅ orElseGet(Supplier<? extends T> supplier)
public T orElseGet(Supplier<? extends T> supplier) {return value != null ? value : supplier.get();
}
🧊 如果
value != null
,根本不会调用supplier.get()
,实现了惰性求值。
🧪 代码实战演示
import java.util.Optional;public class OrElseVsOrElseGet {public static void main(String[] args) {Optional<String> present = Optional.of("Moonshot AI");// ---------- 1. orElse ----------String r1 = present.orElse(getDefault()); // 备胎直接执行!System.out.println("orElse 结果: " + r1);// ---------- 2. orElseGet ----------String r2 = present.orElseGet(() -> getDefault()); // 备胎沉默!System.out.println("orElseGet 结果: " + r2);}private static String getDefault() {System.out.println("🛠️ 备胎启动中...");try { Thread.sleep(1000); } catch (InterruptedException ignored) {}return "备胎本胎";}
}
🖨️ 控制台输出
🛠️ 备胎启动中...
orElse 结果: Moonshot AI
orElseGet 结果: Moonshot AI
虽然 Optional 不为空,但
orElse
还是执行了getDefault()
!
⚠️ 场景速配表
备胎类型 | 推荐方式 | 示例代码 |
---|---|---|
固定字符串 / 数值 | orElse | orElse("默认值") |
查询数据库 / 调远程接口 | orElseGet | orElseGet(() -> dao.query()) |
复杂计算 / I/O 操作 | orElseGet | orElseGet(() -> computeExpensiveResult()) |
✅ 使用建议
优先使用
orElseGet
,性能更稳健orElse
仅适用于非常轻量的默认值(如常量、枚举等)写大型系统时,请避免
orElse(getSomethingBig())
—— 这相当于总是执行了备胎代码,违背了“按需执行”的初衷
📌 小结对比
方法 | 是否惰性 | 性能 | 适用情况 |
---|---|---|---|
orElse | ❌ 否 | 慢(总执行) | 常量、字符串等 |
orElseGet | ✅ 是 | 快(有值不执行) | 重操作、调用外部服务等 |
🔧 延伸:orElseThrow()
才是真正的终极方案
别忘了 Optional
还有个兄弟:
Optional.ofNullable(obj).orElseThrow(() -> new RuntimeException("缺数据!"));
没有值就直接抛异常,不玩备胎这一套。
🧠 思维导图
Optional
├── orElse --> 立即执行(无论是否用到)
├── orElseGet --> 惰性执行(只在为空时)
└── orElseThrow --> 无值抛异常
📎 最佳实践总结
💡 精度优先:能不用就别用
orElse
⚙️ 逻辑清晰:看似相同的方法,可能有截然不同的运行代价
🧪 多测试 Optional 的执行路径,避免隐藏的性能雷