Optional 正确用法
Optional<T> 是可能为空的容器。它的初衷不是「避免写 null 检查」,而是在 API 签名里显式表达『这个值可能没有』,逼调用方思考缺失情况。用错方式(尤其是 .get())反而会制造新的隐患。
1. 反模式:把 Optional 当包装箱
最常见错误是拿到 Optional 后立刻 isPresent() + get(),等于把 null 检查换皮:
// 反模式:多此一举
Optional<User> u = findUser(id);
if (u.isPresent()) {
return u.get().getName();
} else {
return "匿名";
}正确写法用 orElse 直接提供默认值,或 ifPresent 仅在有值时做事:
// 推荐:无值即回退
return findUser(id).map(User::getName).orElse("匿名");
// 仅在存在时执行副作用
findUser(id).ifPresent(u -> System.out.println(u.getName()));⚠️永远不要调用 Optional.get()
get() 在空容器上直接抛 NoSuchElementException。如果代码里出现 get(),几乎一定可以用 orElse / orElseGet / orElseThrow 改写得更安全。
2. orElse 与 orElseGet 的区别
两者都提供回退值,但求值时机不同:
// orElse 的参数「总是」会被计算,即使有值
User u1 = findUser(id).orElse(createDefault()); // createDefault 一定执行
// orElseGet 的 Supplier 仅在「空」时才执行(惰性)
User u2 = findUser(id).orElseGet(() -> createDefault()); // 有值时不执行当回退值创建成本高(查库、建大对象),务必用 orElseGet。
3. flatMap 处理嵌套 Optional
如果映射函数本身返回 Optional,用 map 会得到 Optional<Optional<T>>,此时用 flatMap 展平:
Optional<String> email = findUser(id)
.flatMap(User::getPrimaryEmail) // 返回 Optional<String>
.map(String::toLowerCase);4. 作为返回值,而非字段/参数
💡Optional 的使用边界
- ✅ 适合作为方法返回值,表达『可能无结果』
- ❌ 不要作为类字段(增加序列化与存储成本)
- ❌ 不要作为方法参数(会让调用方被迫包一层)
- ❌ 不要用
Optional给集合类型兜底——空集合比Optional<List>更自然
小结
- ✅
Optional是返回值上的『可能缺失』信号,不是 null 的语法糖 - ✅ 用
orElse/orElseGet/ifPresent,拒绝get() - ✅ 高成本回退用
orElseGet(惰性) - ✅ 嵌套 Optional 用
flatMap展平 - ✅ 只作返回值,不作字段或参数