前言
空指针异常是导致 Java 应用程序失败的最常见原因。以前,为了解决空指针异常,Google 公司著名的 Guava 项目引入了 Optional 类,Guava 通过使用检查空值的方式来防止代码污染,它鼓励程序员写更干净的代码。受到 Google Guava 的启发,Optional 类已经成为 Java8 类库的一部分。Optional 实际上是个容器:它可以保存类型 T 的值,或者仅仅保存 null。Optional 提供很多有用的方法,这样我们就不用显式进行空值检测。
Optional 范例
构造方式
Optional 的三种构造方式:Optional.of(obj),Optional.ofNullable(obj) 和 Optional.empty()。
- Optional.of(),依据一个非空值创建 Optional。
1 | // 如果 car 是一个 null, 这段代码会立即抛出 NullPointException, 而不是等到试图访问 car 的属性值时才返回一个错误. |
- Optional.ofNullable(),可接受 null 的 Optional(实现序列化的域模型时使用)。
1 | // 创建一个允许 null 值的 Optional 对象, 如果 car 是 null, 那么得到的 Optional 对象就是个空对象. |
- Optional.empty(),所有 null 包装成的 Optional 对象。
1 | // 声明一个空的 Optional |
isPresent()/ifPresent(Consumer consumer)
isPresent(),判断值是否存在。
1 | Optional<Integer> optional1 = Optional.ofNullable(1); |
ifPresent(Consumer consumer):如果 option 对象保存的值不是 null,则调用 consumer 对象,否则不调用。
1 | // 如果不是 null, 调用 Consumer; 如果 null, 不调用 Consumer |
orElse(value)/orElseGet(Supplier supplier)
orElse(value):如果 optional 对象保存的值不是 null,则返回原来的值,否则返回 value。
1 | Optional<Integer> optional1 = Optional.ofNullable(1); |
orElseGet(Supplier supplier):功能与 orElse 一样,只不过 orElseGet 参数是一个对象,即无则由函数来产生。
1 | Optional<Integer> optional1 = Optional.ofNullable(1); |
orElseThrow()
orElseThrow():值不存在则抛出异常,存在则什么不做,有点类似 Guava 的 Precoditions。
1 | Optional<Integer> optional = Optional.ofNullable(null); |
filter(Predicate)
filter(Predicate):判断 Optional 对象中保存的值是否满足 Predicate,并返回新的 Optional。
1 | Optional<Integer> optional = Optional.ofNullable(1); |
map(Function)/flatMap(Function)
map(Function) 如果有值,则对其执行调用 mapping 函数得到返回值,否则返回空 Optional。如果返回值不为 null,则创建包含 mapping 返回值的 Optional 作为 map 方法返回值,否则返回空 Optional。
1 | Optional<String> upperName = name.map((value) -> value.toUpperCase()); |
flatMap(Function) 如果有值,为其执行 mapping 函数返回 Optional 类型返回值,否则返回空 Optional。flatMap 与 map(Funtion)方法类似,区别在于 flatMap 中的 mapper 返回值必须是 Optional。调用结束时,flatMap 不会对结果用 Optional 封装。[P.S. 参考博文 [3]:Cascading Optional Objects Using the flatMap Method]
1 | upperName = name.flatMap((value) -> Optional.of(value.toUpperCase())); |
Optional 类的链式方法
错误示范 / 正确示范
- 示范(一)
1 | // ** 错误示范 |
- 示范(二)
1 | // ** 错误示范 |
参考博文
[1]. Java 8 Optional 类深度解析
[2]. 使用 Java8 Optional 的正确姿势
[3]. Tired of Null Pointer Exceptions? Consider Using Java SE 8’s Optional!
Java8 那些事儿系列
- Java8 那些事儿(一):Stream 函数式编程
- Java8 那些事儿(二):Optional 类解决空指针异常
- Java8 那些事儿(三):Date/Time API(JSR 310)
- Java8 那些事儿(四):增强的 Map 集合
- Java8 那些事儿(五):函数式接口
- Java8 那些事儿(六):从 CompletableFuture 到异步编程