面试知识库
基础

Optional用法#

一句话答案#

Optional 是 JDK 8 引入的容器,用来显式表达”值可能为空”,通过 map/filter/orElse/ifPresent 链式处理,优雅规避 NPE;最佳实践是作返回值,不作字段和方法参数。

核心要点

1. 创建

Optional.of(value);          // value 不能为 null,否则 NPE
Optional.ofNullable(value);  // value 可为 null(推荐用于不确定的场景)
Optional.empty();            // 空容器
java

2. 取值与默认值

opt.get();                   // 空时抛 NoSuchElementException —— 慎用!
opt.orElse(defaultVal);      // 空则返回默认值(无论是否空都会求值)
opt.orElseGet(() -> compute());   // 空时才执行 supplier(惰性,推荐)
opt.orElseThrow(() -> new BizException());  // 空则抛指定异常
java

3. 链式处理(核心价值)

// 传统层层判空
String city = user != null && user.getAddr() != null ? user.getAddr().getCity() : "未知";
// Optional 链式
String city = Optional.ofNullable(user)
        .map(User::getAddr)
        .map(Addr::getCity)
        .orElse("未知");
java
  • map:值存在则转换,否则保持空。
  • filter:值存在且满足条件才保留。
  • flatMap:转换结果本身是 Optional 时用它避免嵌套 Optional<Optional<>>
  • ifPresent(consumer):存在则消费。

4. 最佳实践与反模式

✅ 推荐❌ 反模式
作方法返回值表达”可能无结果”作类字段(不可序列化、增内存)
orElseGet 惰性求默认值isPresent()+get()(退化成判空)
map 链式转换直接 get() 不判空(等于没用)
orElseThrow 表达业务异常作方法参数(调用方还得包一层)
面试回答(2分钟版)

Optional 是 JDK 8 引入的一个容器类,用来显式地表达一个值可能存在也可能为空,目的是从语法层面规避空指针异常,同时让”可能为空”这件事在 API 签名上变得明确。创建有三种方式:of 要求值非空否则直接抛异常,ofNullable 允许传 null,empty 是空容器。取值时最该避免的是直接调 get,因为空的时候会抛 NoSuchElementException,跟空指针没区别。推荐用 orElse 给默认值,或者 orElseGet 传一个 supplier 惰性求值——注意 orElse 不管空不空都会先把默认值算出来,orElseGet 只有空的时候才执行,性能更好。Optional 真正的价值在链式处理,配合 map、filter、flatMap 可以把传统层层判空的代码写成一条流畅的链,比如取用户地址里的城市,一路 map 下去最后 orElse 一个默认值,任何一环为空都安全短路。最佳实践方面:Optional 适合作方法返回值表达可能无结果,但不建议作类的字段,因为它没实现 Serializable 还增加内存,也不建议作方法参数,会让调用方很别扭。最大的反模式是用 isPresent 加 get,那等于把 Optional 又退化成了 if 判空,完全没发挥它的作用。

追问与易错

追问方向:

  • “orElse 和 orElseGet 区别?”→ orElse 的默认值无论是否为空都会被求值;orElseGet 的 supplier 只在为空时执行,涉及昂贵计算时用 orElseGet
  • “为什么不推荐 Optional 作字段?”→ 未实现 Serializable,序列化受限;每个字段多包一层对象增加内存;语义上字段为空用 null 即可
  • “map 和 flatMap 区别?”→ map 的函数返回普通值会自动包成 Optional;若函数本身返回 Optional 用 flatMap 避免 Optional 嵌套
  • “Optional 能彻底消除 NPE 吗?”→ 不能。误用 get 或对 Optional 本身为 null 仍会出问题,它只是工具不是银弹
  • “Optional 是值类型吗?”→ 是基于值的类(value-based),不应对其做同步或用 == 比较

易错点:

  • isPresent() + get()——退化成判空,应直接 map/orElse
  • Optional.of(可能为null的值)——会抛 NPE,不确定时用 ofNullable
  • ❌ 把 Optional 当字段或参数——只作返回值
  • ❌ 昂贵默认值用 orElse——应用 orElseGet 惰性求值