10.3 应用Optional的几种模式

10.3.1 创建Optional对象

  1. 创建一个空的Optional:Optional<Car> optCar = Optional.empty();

  2. 依据一个非空值创建Optional:Optional<Car> optCar = Optional.of(car); 注意car为null,创建会报NPE

  3. 可接受null的Optional:Optional<Car> optCar = Optional.ofNullable(car); 包含1和2两种情形

Optional#get获取封装的变量,若为空Optional,会抛出java.util.NoSuchElementException: No value present,因此Optional的使用也有约定。

Optional类和Stream接口在map,flatMap,filter的行为极其相似。

跟Stream操作类似,首先从无需显式检查的Optional值的使用入手。

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

把Optional对象看成一种特殊的集合数据,它至多包含一个元素。

  • 如果Optional包含一个值,那函数就将该值作为参数传递给map,对该值进行转换。
  • 如果Optional为空,就什么也不做。
String name = null;
if (insurance != null) {
    name = insurance.getName();
}
Optional<Insurance> optInsurance = Optional.ofNullable(insurance);
Optional<String> name = optInsurance.map(Insurance::getName);

10.3.3 使用flatMap链接Optional对象

Optional<Car> car = person.getCar();
Optional<Optional<Insurance>> insurance = car.map(Car::getInsurance);

因为Car#getInsurance返回一个optional对象,使用map会导致Optional嵌套对象

跟Stream类似,使用flatMap会消除嵌套

Optional<Car> car = person.getCar();
Optional<Insurance> insurance = car.flatMap(Car::getInsurance);

基于Optional重写10.1.1,其中orElse为空Optional提供默认值

public String getCarInsuranceName(Person person) {
    return Optional.ofNullable(person).flatMap(Person::getCar)
            .flatMap(Car::getInsurance)
            .map(Insurance::getName).orElse("Unknown");
}

在域模型中使用Optional,以及为什么它们无法序列化

Optional设计初衷仅支持能返回Optional对象的语法,不建议作为类的字段使用,因此设计上也未实现Serializable接口,序列化会导致报错。

Optional使用上不建议作为实体类的字段(getter方法可返回Optional),方法的入参(可额外入参默认值)

public class Person {
  private Car car;
  public Optional<Car> getCarAsOptional() {
      return Optional.ofNullable(car);
  }

  public Insurance getCarAsOptional(Car car, Insurance defaultInsurance) {
      return Optional.ofNullable(car).map(Car::Insurance).orElse(defaultInsurance);
  }
}

10.3.4 默认行为及解引用Optional对象

Optional类提供了多种方法读取Optional实例中的变量值。

  • get():
    1. 变量值存在时,返回封装的变量值;
    2. 变量值不存在时,抛出NoSuchElementException异常;
  • orElse(T other)
    1. 变量值存在时,返回封装的变量值;
    2. 变量值不存在时,提供默认值;
  • orElseGet(Supplier<? extends T> other)
    1. 变量值存在时,返回封装的变量值;
    2. 变量值不存在时,调用Supplier生成对象返回;
  • orElseThrow(Supplier<? extends X> exceptionSupplier)
    1. 变量值存在时,返回封装的变量值;
    2. 变量值不存在时,调用Supplier抛出指定的异常类型;
  • ifPresent(Consumer<? super T>)
    1. 变量值存在时,执行Consumer操作
    2. 变量值不存在时,不进行任何操作;

10.3.5 两个Optional对象的组合

public Insurance findCheapestInsurance(Person person, Car car) {
    // 不同的保险公司提供的查询服务
    // 对比所有数据
    Insurance cheapestCompany = null;
    return cheapestCompany;
}

public Optional<Insurance> nullSafeFindCheapestInsurance(Optional<Person> person, Optional<Car> car) {
    if (person.isPresent() && car.isPresent()) {
        return Optional.of(findCheapestInsurance(person.get(), car.get()));
    } else {
        return Optional.empty();
    }
}

测验10.1:以不解包的方式组合两个Optional对象

public Optional<Insurance> nullSafeFindCheapestInsurance2(Optional<Person> person, Optional<Car> car) {
    return person.flatMap(p -> car.map(c -> findCheapestInsurance(p, c)));
}

跟null判空类似,基于map和flatMap重构,个人感觉可读性变差

10.3.6 使用filter剔除特定的值

Insurance insurance = new Insurance();
if (insurance != null && "CambridgeInsurance".equals(insurance.getName())) {
    System.out.println("ok");
}

filter过滤Optional对象

  1. 变量值存在时,执行predicate条件是否通过,注意predicate为空会报NPE;
  2. 变量值不存在时,直接返回Optional.empty();
Insurance insurance = new Insurance();
Optional.ofNullable(insurance).filter(ele -> "CambridgeInsurance".equals(insurance.getName()))
        .ifPresent(ele -> System.out.println("ok"));

测验10.2:对Optional对象进行过滤

假设在我们的Person/Car/Insurance模型中,Person还提供了一个方法可以取得Person对象的年龄,请使用下面的签名改写代码中的getCarInsuranceName方法:

public String getCarInsuranceName(Optional<Person> person, int minAge);

找出年龄大于或者等于minAge参数的Person所对应的保险公司列表。

public String getCarInsuranceName(Optional<Person> person, int minAge) {
    return person.filter(ele -> ele.getAge() >= minAge)
            .flatMap(Person::getCar)
            .flatMap(Car::getInsurance)
            .map(Insurance::getName)
            .orElse("Unknown");
}

Optional类中的方法小结。

方法 描述
empty 返回Optional空实例
filter 若值存在且满足predicate,返回该Optional对象,否则返回Optional空实例
flatMap 若值存在且执行mapping,返回内层Optional对象,否则返回Optional空实例
get 若值存在,返回封装值,否则抛出NoSuchElementException
ifPresent 若值存在,执行consumer,否则不进行任何操作
isPresent 判断值是否存在
map 若值存在且执行mapping,返回Optional对象,否则返回Optional空实例
of 若值存在,返回封装值的Optional,否则抛出NullPointerException
ofNullable 若值存在,返回封装值的Optional,否则返回Optional空实例
orElse 若值存在,返回值,否则返回指定默认值
orElseGet 若值存在,返回值,否则返回supplier生成的值
orElseThrow 若值存在,返回值,否则抛出supplier生成的异常

引用

  1. 面试官:Java Optional 为什么设计成不可序列化的?
posted @ 2023-05-28 14:05  蒋智  阅读(33)  评论(0)    收藏  举报