Optional
创建 Optional 值
如果想要编写方法来创建 Optional 对象,那么有多个方法可以用于此目的,具体如下:
public static<T> Optional<T> empty()
public static <T> Optional<T> of(T value)
public static <T> Optional<T> ofNullable(T value)
ofNullable() 方法被用来作为可能出现的 null 值和可选值之间的桥梁。of() 方法如果传入的 value 为 null,则会抛出一个 NullPointerException 异常。ofNullable() 方法会在 obj 不为 null 的情况下返回 Optional.of(obj),否则会返回 Optional.empty()。
获取 Optional 值
有效地使用 Optional 的关键是要使用这样的方法:它在值不存在的情况下会产生一个可替代物,而只有在值存在的情况下才会使用这个值。
// 产生这个 Optional 的值,或者在该 Optional 为空时,产生 other
public T orElse(T other)
// 产生这个 Optional 的值,或者在该 Optional 为空时,产生调用 other 的结果
public T orElseGet(Supplier<? extends T> other)
// 产生这个 Optional 的值,或者在该 Optional 为空时,抛出调用 exceptionSupplier 的结果
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X
// 如果该 Optional 不为空,就将它的值传递给 consumer 进行处理,如果值为空则不做任何处理
public void ifPresent(Consumer<? super T> consumer)
管道化 Optional 值
除了可以从 Optional 对象中获取值,我们还可以保持 Optional 对象的完整,使用 map 等方法来转换 Optional 内部的值。
// 产生一个 Optional,如果当前的 Optional 的值得在,那么所产生的 Optional 的值是通过将给定的函数应用于当前的 Optional 的值而得到的
// 否则,产生一个空的 Optional
public <U> Optional<U> map(Function<? super T, ? extends U> mapper)
这个 map() 方法与 Stream 接口提供的 map() 方法类似。你可以直接将可选值想象成尺寸为 0 或 1 的流。结果的尺寸也是 0 或 1,并且如果流的尺寸为 1 时,mapper 函数会应用于其上。
类似地,可以使用 filter 方法来只处理那些在转换它之前或之后满足某种特定属性的 Optional 值。如果不满足该属性,那么管道会产生空的结果:
// 产生一个Optional,如果当前的 Optional 的值满足给定的谓词条件,那么所产生的Optional 的值就是当前 Optional 的值
// 否则产生一个空 Optional
public Optional<T> filter(Predicate<? super T> predicate)
使用示例:
private List<String> rightMethod(FooService fooService, Integer i) {
log.info("result {} {}", Optional.ofNullable(i).orElse(0) + 1);
Optional.ofNullable(fooService)
.map(FooService::getBarService)
.filter(barService -> "OK".equals(barService.bar()))
.ifPresent(result -> log.info("OK"));
return new ArrayList<>();
}
注意事项
如果没有正确地使用 Optional 值,那么相比普通对象并没有得到任何好处。get() 方法会在 Optional 值存在的情况下获得其中包装的元素,或者在不存在的情况下抛出一个 NoSuchElementException 异常。因此,直接调用 get() 方法获取元素并不比获取普通对象更安全。
下面是一些有关 Optional 类型正确用法的提示:
- Optional 类型的变量永远都不应该为 null
- 不要使用 Optional 类型的域。因为其代价是额外多出来一个对象。在类的内部,使用 null 表示缺失的域更易于操作。
- 不要在集合中放置 Optional 对象,并且不要将它们用作 map 的键,应该直接收集其中的值。