Optional 的正确用法
Optional 的不正确实践
显式 if-else 本身合法。取得 Optional 中的 User 后,才能调用 User 的方法;Optional<User> 没有 getOrders():
1 | |
get() 在 empty 时抛出 NoSuchElementException;此例先检查存在性。如果只需要映射结果和缺省值,map(...).orElseGet(...) 可以减少显式解包。
Optional 主要用于可能无结果的方法返回值。用作 POJO 字段时需核对序列化、持久化与框架绑定契约,不因字段用了 Optional 就推导框架支持。
参数是否使用 Optional 取决于调用契约。调用者需要明确传入“缺席”时可以采用这种签名;普通必填参数直接使用领域类型,不额外包装。
Optional 表达有值或无值。布尔条件可直接分支;多种业务错误需要不同原因时采用结构化结果。存在多个返回路径并不构成禁止使用 Optional 的理由。
正确的用法
选对构造器
Optional.of(T value)
如果需要断言值不为空,使用这个构造器。
该方法通过一个非 null 的 value 来构造一个 Optional,返回的 Optional 包含了 value 这个值。对于该方法,传入的参数一定不能为 null,否则便会抛出 NullPointerException。
Optional.ofNullable(T value)
如果这个值可以为空,使用这个构造器。
该方法和 of 方法的区别在于,传入的参数可以为 null , 但是前面 javadoc 不是说 Optional 只能包含非 null 值吗?原来该方法会判断传入的参数是否为 null,如果为 null 的话,返回的就是 Optional.empty()。
Optional.empty()
empty() 表达无结果,也可以直接作为方法返回值。
empty() 返回不包含值的 Optional。API 表达有值与无值两种情况,不应依赖内部字段,也不能假设所有 empty 都有同一对象身份。
选对返回值
orElse 与 orElseGet 在缺席时提供值,区别在默认值的求值时机:传给 orElse 的表达式先求值,orElseGet 的 Supplier 仅在缺席时执行。map 映射普通值,flatMap 接续返回 Optional 的函数;collect 属于 Stream,Optional 没有该方法,也不采用 Stream 的终端操作分类。
1 | |
选对消费者
ifPresent 在有值时执行 Consumer,适合明确的副作用边界。它不会返回转换后的 Optional,也不提供通用 Continuation 的控制流能力。显式存在性分支同样合法,按分支的复杂度选择。
1 | |
Java 9 对Optional的增强
or方法
or 方法的作用是,如果一个 Optional 包含值,则返回自己;否则返回由参数 supplier 获得的 Optional
ifPresentOrElse
ifPresentOrElse 方法的用途是,如果一个 Optional 包含值,则对其包含的值调用函数 action,即 action.accept(value),这与 ifPresent 一致;与 ifPresent 方法的区别在于,ifPresentOrElse 还有第二个参数 emptyAction —— 如果 Optional 不包含值,那么 ifPresentOrElse 便会调用 emptyAction,即 emptyAction.run()
stream
stream 方法的作用就是将 Optional 转为一个 Stream,如果该 Optional 中包含值,那么就返回包含这个值的 Stream;否则返回一个空的 Stream(Stream.empty())。
Java 8 可通过过滤与解包取得所有存在的 User:
1 | |
Java 9 起可以使用 Optional.stream():
1 | |
当前版本的复现与阅读
上述核心类型与 null 边界已在 JDK 21 复现:编译与运行入口、运行记录。反例检查 Optional 直接调用 getOrders 编译失败、of(null) 与 flatMap 返回 null 抛异常;正例检查存在/缺席、默认值求值与 Optional.stream 展平。getOrders() 非 null 时,示例分支与 map 链返回相同列表;实验另检查 getter 返回 null 时的差异:分支直接返回 null,map 将其变为缺席,再返回空列表。代码片段中的 User、findUser、getUserById 是业务上下文占位,完整实验自带最小 User 类型。
Maybe 与组合推导从函数式编程系列导读进入。Optional 的返回值定位及 map/flatMap 的 null 规则以 JDK 21 API 为准。本文保留原标题、日期和公开地址。
参考文献:




