Java 8中引入了一个新的类java.util.Optional<T>。变量存在时,Optional类只是对类简单封装。变量不存在时,缺失的值会被建模成一个“空”
的Optional对象,由方法Optional.empty()返回。java
正如前文已经提到,你能够经过静态工厂方法Optional.empty,建立一个空的Optional对象:安全
Optional<Car> optCar = Optional.empty();
你还可使用静态工厂方法Optional.of,依据一个非空值建立一个Optional对象:函数
Optional<Car> optCar = Optional.of(car);
若是car是一个null,这段代码会当即抛出一个NullPointerException,而不是等到你试图访问car的属性值时才返回一个错误。性能
最后,使用静态工厂方法Optional.ofNullable,你能够建立一个容许null值的Optional对象:spa
Optional<Car> optCar = Optional.ofNullable(car);
若是car是null,那么获得的Optional对象就是个空对象。设计
Optional提供了一个 get方法用于获取Optional变量中的值,不过get方法在遭遇到空的Optional对象时也会抛出异常,因此不按照约定的方式使用它,又会让咱们再度陷入由null引发的代码维护的梦魇。
好比,你可能想要从insurance公司对象中提取公司的名称。提取名称以前,你须要检查insurance对象是否为null,代码以下所示:code
String name = null; if(insurance != null){ name = insurance.getName(); }
用Optional实现:对象
Optional<Insurance> optInsurance = Optional.ofNullable(insurance); Optional<String> name = optInsurance.map(Insurance::getName);
原理示意:接口
Optional<Person> optPerson = Optional.of(person); Optional<String> name = optPerson.map(Person::getCar) //编译没法经过 .map(Car::getInsurance) .map(Insurance::getName);
不幸的是,这段代码没法经过编译。为何呢?optPerson是Optional<Person>类型的变量, 调用map方法应该没有问题。但getCar返回的是一个Optional<Car>类型的对象,这意味着map操做的结果是一个Optional<Optional<Car>>类型的对象。所以,它对getInsurance的调用是非法的,由于最外层的optional对象包含了另外一个optional对象的值,而它固然不会支持getInsurance方法。
正确作法:图片
public String getCarInsuranceName(Optional<Person> person) { return person.flatMap(Person::getCar) .flatMap(Car::getInsurance) .map(Insurance::getName) //Insurance::getName返回的是String类型,不是Optional //返回的Optional多是两种状况:若是调用链上的任何一个 //方法返回一个空的Optional,那么结果就为空,不然返回的值就是你指望的保险公司的名称。 .orElse("Unknown"); }
在域模型中使用Optional,以及为何它们没法序列化
因为Optional类设计时就没特别考虑将其做为类的字段使用,因此它也并未实现Serializable接口。
若是你必定要实现序列化的域模型,做为替代方案,咱们建议你像下面这个例子那样,提供一个能访问声明为Optional、变量值可能缺失的接口,代码清单以下:public class Person { private Car car; public Optional<Car> getCarAsOptional() { return Optional.ofNullable(car); } }
Optional类提供了多种方法读取Optional实例中的变量值。
public Insurance findCheapestInsurance(Person person, Car car) { // 不一样的保险公司提供的查询服务 // 对比全部数据 return cheapestCompany; }
public Optional<Insurance> nullSafeFindCheapestInsurance( Optional<Person> person, Optional<Car> car) { return person.flatMap(p -> car.map(c -> findCheapestInsurance(p, c))); }
这段代码中,你对第一个Optional对象调用flatMap方法,若是它是个空值,传递给它的Lambda表达式不会执行,此次调用会直接返回一个空的Optional对象。反之,若是person对象存在,此次调用就会将其做为函数Function的输入,并按照与flatMap方法的约定返回一个Optional<Insurance>对象。这个函数的函数体会对第二个Optional对象执行map操做,若是第二个对象不包含car,函数Function就返回一个空的Optional对象,整个nullSafeFindCheapestInsuranc方法的返回值也是一个空的Optional对象。最后,若是person和car对象都存在,做为参数传递给map方法的Lambda表达式可以使用这两个值安全地调用原始的findCheapestInsurance方法,完成指望的操做。
Optional<Insurance> optInsurance = ...; optInsurance.filter(insurance -> "CambridgeInsurance".equals(insurance.getName())) .ifPresent(x -> System.out.println("ok"));
filter方法接受一个谓词做为参数。若是Optional对象的值存在,而且它符合谓词的条件,
filter方法就返回其值;不然它就返回一个空的Optional对象。
Optional类的方法:
与 Stream对象同样,Optional也提供了相似的基础类型——OptionalInt、OptionalLong以及OptionalDouble,若是Stream对象包含了大量元素,出于性能的考量,使用基础类型是不错的选择,但对Optional对象而言,这个理由就不成立了,由于Optional对象最多只包含一个值。咱们不推荐你们使用基础类型的Optional,由于基础类型的Optional不支持map、flatMap以及filter方法,而这些倒是Optional类最有用的方法。