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 的判断。

相关推荐
A 小码农1 小时前
亲测AI智能小助手-IDEA中使用腾讯混元大模型
java·人工智能·intellij-idea
eggwyw2 小时前
redis 使用
java
ERBU DISH2 小时前
ChatGLM2-6B模型推理流程和模型架构详解
java
码云数智-园园2 小时前
关系型与非关系型数据库:核心区别与业务场景解析
数据库·oracle
BullSmall2 小时前
IntelliJ IDEA 安装与环境配置指南(2026 最新)
java·ide·intellij-idea
Javatutouhouduan2 小时前
SQL优化从入门到精通!
java·数据库·mysql·sql优化·java面试·后端开发·java程序员
jnrjian2 小时前
restore archivelog RAC thread from sequence logseq
服务器·数据库
小草儿7992 小时前
PG18之插件使用大全(简单用例)
数据库
Elastic 中国社区官方博客2 小时前
从 Elasticsearch runtime fields 到 ES|QL:将传统工具适配到当前技术
大数据·数据库·sql·elasticsearch·搜索引擎·全文检索