为什么引入Optional

避免深层次的null防御代码,提高代码可读性(要在实践中体会。笔者看过Optional很多次,一直都不能理解怎么就能避免深层次的null防御代码,直到在项目中频繁使用之后才有点认识)

可以通过抛出异常再捕获的方式来处理null分支。除非这确实是异常情况,否则不建议这么做。不要使用异常来处理正常的逻辑分支。虽然少了一层null判断,但代码更丑陋。

Optional的几种使用方式

创建Optional对象

  • 声明空对象 Optional<Car> optianlCar = Optional.empty();
  • 非空值创建 Optional<Car> optianlCar = Optional.of(car);
  • 可为空值创建 Optional<Car> optianlCar = Optional.ofNullable(car);

使用map从Optional对象中提取和转化值

  1. Optional<Insurance> optInsurance = Optional.ofNullable(insurance);
  2. Optional<String> name = optInsurance.map(Insurance::getName);

使用flatMap链接Optional对象

Optional<Person> optPersion = Optional.of(persion);
Optional<String> name =
    optPersion.map(Persion::getCar)
              .map(Car::getInsurance)
              .map(Insurance::getName); //构建不通过


Optional<String> name =
    optPersion.flatMap(Persion::getCar)
              .flatMap(Car::getInsurance)
              .map(Insurance::getName);

public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
    Objects.requireNonNull(mapper);
    if (!isPresent())
        return empty();
    else {
        return Optional.ofNullable(mapper.apply(value));
     }
}

public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
    Objects.requireNonNull(mapper);
    if (!isPresent())
        return empty();
    else {
        return Objects.requireNonNull(mapper.apply(value));
    }
}

方法集合

empty 返回空的 Optional 实例。
filter 如果值存在且满足提供的谓词,返回一个包含该值的Optional对象,否则返回一个空的Optional。
flatMap 如果值存在,就对该值执行提供的mapping函数调用,返回一个Optional对象,否则返回一个空的Optional。
get 如果值存在,将该值用Optional封装返回,否则抛出异常:NoSuchElementException
ifPresent 如果值存在,就执行使用该值的方法调用,否则什么也不做
isPresent 如果值存在就返回true,否则返回false
map 如果值存在,就对该值执行提供的mapping函数调用
of 将指定值用Optional封装之后返回,如果该值为null,则抛出一个NullPointerException异常
ofNullable 将指定值用Optional封装之后返回,如果该值为null,则返回一个空的Optional对象
orElse 如果优质则将其返回,否则返回一个默认值
orElseGet 如果优质将其返回,否则返回一个由指定Supplier接口生成的值
orElseThrow 如果优质则将其返回,否则抛出一个由指定的Supplier接口生成的值

零碎知识

Optional.empty()有什么特点

这个方法返回的是Optional的静态变量。

private static final Optional<?> EMPTY = new Optional<>();

public static<T> Optional<T> empty() {
    @SuppressWarnings("unchecked")
    Optional<T> t = (Optional<T>) EMPTY;
    return t;
}

定义EMPTY时使用的是泛型,因此下面两个变量指向的是同一个实例

Optional<String> str = Optional.empty();
Optional<Integer> number = Optional.empty();
System.out.println(str.equals(number)); // 结果是true

Optional.ofNullable(null)和Optional.empty()的区别

这两者是同一个东西。都指向Optional类中的静态类变量EMPTY。

    public static <T> Optional<T> ofNullable(T value) {
        return value == null ? empty() : of(value);
    }

不适合做类的字段和函数参数

Optional设计的目的就是为某些需要清楚的表达结果不存在的库方法的返回类型提供一种限制性的结构。并且当类需要序列化时,Optional也会出现问题,因为Optional无法被序列化(渣渣翻译,将就着看)。IDEA中提示的原文如下:
Reports any uses of java.util.Optional, java.util.OptionalDouble, java.util.OptionalInt, java.util.OptionalLong or com.google.common.base.Optional as the type for a field or a parameter. Optional was designed to provide a limited mechanism for library method return types where there needed to be a clear way to represent “no result”. Using a field with type java.util.Optional is also problematic if the class needs to be Serializable, which java.util.Optional is not.
我在《Java8 实战》一书中看到Optional作为类字段的范例,所以尝试这么用过。现在看来,正常的设置类字段,在get方法中使用Optional.ofNullable(field)来返回字段更为合适。