10.3 应用Optional的几种模式
10.3.1 创建Optional对象
-
创建一个空的Optional:
Optional<Car> optCar = Optional.empty(); -
依据一个非空值创建Optional:
Optional<Car> optCar = Optional.of(car);注意car为null,创建会报NPE -
可接受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():
- 变量值存在时,返回封装的变量值;
- 变量值不存在时,抛出NoSuchElementException异常;
- orElse(T other)
- 变量值存在时,返回封装的变量值;
- 变量值不存在时,提供默认值;
- orElseGet(Supplier<? extends T> other)
- 变量值存在时,返回封装的变量值;
- 变量值不存在时,调用Supplier生成对象返回;
- orElseThrow(Supplier<? extends X> exceptionSupplier)
- 变量值存在时,返回封装的变量值;
- 变量值不存在时,调用Supplier抛出指定的异常类型;
- ifPresent(Consumer<? super T>)
- 变量值存在时,执行Consumer操作;
- 变量值不存在时,不进行任何操作;
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对象
- 变量值存在时,执行predicate条件是否通过,注意predicate为空会报NPE;
- 变量值不存在时,直接返回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生成的异常 |

浙公网安备 33010602011771号