从对象中读取信息是一种比较常见的模式。比如,你可以从insurance公司对象中提取公司的名称。提取名称之前你需要检查insurance对象是否为null,如:
String name = null;
if(insurance != null){
name = insurance.getName();
}
为了支持这种模式,Optional提供了一个map方法。
Optional<Insurance> optionalInsurance = Optional.ofNullable(insurance);
Optional<String> name = optionalInsurance.map(Insurance::getName);
这里的map和流中的map相差无几。map操作会将提供的函数应用于流的每个元素。你可以把Optional对象看成一种特殊的集合数据。如图:
这看齐来挺有用,但是如何应用起来,重构之前的代码呢?
p.getCar().getInsurance().getName();
使用flatMap链接Optional对象
使用刚刚的学习的map,第一反应是重写之前的代码,比如这样:
Optional<Person> person = Optional.of(p);
Optional<String> name = person
.map(Person::getCar)
.map(Car::getInsurance)
.map(Insurance::getName);
但是这段代码无法通过编译,person是Optional<Person>类型的变量,调用map方法没有问题,但是getCar返回的是一个Optional<Car>类型的对象,这意味着map操作的结果的结果是一个Optional<Optinoal<Car>>类型的对象。 因此它调用getInsurance是非法的。
在流中使用flatMap可以扁平化合并流,在这里你想把两层的Optional合并为一个。
public String getCarInsuranceName(Person p) {
Optional<Person> person = Optional.of(p);
return person
.flatMap(Person::getCar)
.flatMap(Car::getInsurance)
.map(Insurance::getName)
.orElse("Unknown");
}
通过代码的比较,处理潜在可能缺失的值时,使用Optional具有明显的优势。你可以非常容易实现期望的效果,不需要写那么多的条件分支,也不会增加代码的复杂性。
首先,Optional.of(p) 生成Optional<person>对象,然后调用person.flatMap(Person::GetCar)返回一个Optional<Car> 对象,Optional内的Person也被转换成了这种对象,结果就是两层的Optional对象,最终他们会被flatMap操作合并起来。如果合并时其中有一个为空,那么就构成一个空的Optional对象。如果给一个空的Optional对象调用flatMap返回的也是空的Optional对象。
然后,flatMap(Car::getInsurance) 会转换成Optional<Insurance> 合并。 第三步 这里调用的是map方法,因为返回类型是string 就不需要flatMap了。如果连上的任何一个结果为空就返回空,否则返回的值就是期望的值。 所以最后用了一个orElse的方法,当Optional为空的时候返回一个默认值。
获取Optional对象的值:
1. get() 是这些方法中最简单但最不安全的方法。如果变量存在,直接返回封装的变量值。否则抛出一个NoSuchElementException异常。
2. orElse(T other) 默认值,当值存在返回值,否则返回此默认值。
3. orElseGet(Supplier<? extends T> other) 是orElse方法的延迟调用版,Supplier方法只有在Optional对象不含值时才执行调用。
4. orElseThrow(Supplier<? extends X> exceptionSupplier )和get方法相似,遇到Optional对象为空时都抛出一个异常,使用orElseThrow可以自定义异常类型。
5. ifPresent(Consumer<? super T>) 在变量值存在时执行,否则什么都不做。
判断Optional是否有值 isPresent()
假设有一个方法,接受两个参数 Person 和Car 来查询便宜的保险公司:
public Insurance getInsurance(Person person ,Car car){
//业务逻辑
return new Insurance();
}
这是以前的版本,使用我们今天所学的知识 可以做一个安全版本,它接受两个Optional对象作为参数 返回值也是一个Optional<Insurance>方法: