Java Optional 那些被忽略的用法

很多人用 Optional 就是 ifPresent,稍微好一点会用 orElse。但 Optional 其实有不少好用的方法,一直没被充分利用。

一、orElse vs orElseGet 别搞混

这两个都会在 Optional 为空时返回默认值,但有个关键区别:

java 复制代码
// orElse:无论是否为空,orElse 的参数都会执行
String a = Optional.ofNullable(getName()).orElse(getDefaultName());
// 等同于:getName() ?? getDefaultName()
// 不管 getName() 返回什么,getDefaultName() 一定会被调用

// orElseGet:只有为空时才执行
String b = Optional.ofNullable(getName()).orElseGet(() -> getDefaultName());
// 只有 getName() 为空时,getDefaultName() 才会被调用

如果 getDefaultName() 是从数据库查或者调用接口,这个差别就大了。日常开发里 orElseGet 性能更好,但容易被忽略。

二、filter 过滤不要的条件

这个组合很多人不知道:

java 复制代码
// 传统写法
if (user != null && user.getAge() >= 18) {
    doSomething(user);
}

// Optional 写法
Optional.ofNullable(user)
    .filter(u -> u.getAge() >= 18)
    .ifPresent(this::doSomething);

filter 会把不满足条件的 Optional 变成空,后面的操作自然跳过。

三、map 链式取值,告别层层判空

这应该是 Optional 最核心的用法:

java 复制代码
// 传统写法:每一层都可能为空
String city = null;
if (user != null) {
    if (user.getAddress() != null) {
        city = user.getAddress().getCity();
    }
}

// Optional 写法:一行搞定
String city = Optional.ofNullable(user)
    .map(User::getAddress)
    .map(Address::getCity)
    .orElse("未知");

每一层 map 遇到空值就中断,最后返回空 Optional,不会抛 NPE。

四、flatMap 处理列表

java 复制代码
// 从用户里取订单,再从订单里取商品
// 传统写法
if (user != null && user.getOrders() != null && !user.getOrders().isEmpty()) {
    Product product = user.getOrders().get(0).getProduct();
}

// flatMap 写法
Optional.ofNullable(user)
    .flatMap(u -> u.getOrders().stream().findFirst())
    .map(Order::getProduct);

flatMap 的特点是返回的还是 Optional,适合用在需要二次转换的场景。

五、orElseThrow 有预期地抛异常

当值为空时,不给默认值,而是抛自定义异常:

java 复制代码
User user = Optional.ofNullable(userId)
    .map(this::findById)
    .orElseThrow(() -> new BizException("用户不存在"));

orElse(null) 强多了,至少是个明确的异常而不是后面的 NPE。

六、ifPresentOrElse 兼顾两种情况

JDK 9 引入的,有值和没值分别处理:

java 复制代码
Optional.ofNullable(user)
    .ifPresentOrElse(
        u -> System.out.println("欢迎 " + u.getName()),
        () -> System.out.println("用户不存在")
    );

以前要写 if-else,现在一行搞定。

七、Optional 不是银弹

Optional 适合用在方法返回值链式处理上,但别滥用:

java 复制代码
// 不建议:成员变量用 Optional
private Optional<String> name;  // 序列化麻烦

// 不建议:参数用 Optional
void getUser(Optional<Long> userId);  // 调用方还得包装

// 不建议:集合用 Optional
private Optional<List<String>> names;  // 空集合比 Optional 更合理

Optional 的定位是库方法返回值,避免调用方 NPE,不是用来改造整个代码结构的。

总结

方法 用途 容易被忽略程度
orElseGet 延迟计算默认值 ⭐⭐⭐
filter 过滤不要的值 ⭐⭐⭐
flatMap 处理列表/二次转换 ⭐⭐⭐⭐
orElseThrow 空时抛明确异常 ⭐⭐⭐
ifPresentOrElse 兼顾有无两种情况 ⭐⭐

用好 Optional 能让代码整洁很多,至少不用写一堆 != null 的判断。

相关推荐
辞旧 lekkk10 小时前
【Qt】信号和槽
linux·开发语言·数据库·qt·学习·mysql·萌新
zc.z10 小时前
JAVA实现:纯PCM格式音频转换成BASE64
java·音视频·pcm
mask哥10 小时前
力扣算法java实现汇总整理(上)
java·算法·leetcode
2301_8092047011 小时前
JavaScript中严格模式use-strict对引擎解析的辅助.txt
jvm·数据库·python
zjy2777711 小时前
mysql如何选择合适的索引类型_mysql索引设计实战
jvm·数据库·python
Aaswk11 小时前
Java Lambda 表达式与流处理
java·开发语言·python
是宇写的啊12 小时前
Spring AOP
java·spring
笨蛋不要掉眼泪12 小时前
Mysql架构揭秘:update语句的执行流程
数据库·mysql·架构
万邦科技Lafite12 小时前
京东item_get接口实战案例:实时商品价格监控全流程解析
java·开发语言·数据库·python·开放api·淘宝开放平台
秋912 小时前
ruoyi项目更换为mysql9.7.0数据库
数据库