一. 用Optional取代nulljava
1. Optional类安全
java.util.Optional<T>是一个封装Optional值的类。app
变量存在时,Optional类只是对类进行简单的封装。变量不存在时,缺失的值会被建模成一个“空”的Optional对象,由方法Optional.empty()返回。ide
Optional.empty()方法是一个静态工厂方法,它返回Optional类的特定单一实例。函数
使用Optional而不是null的一个很是重要而又实际的语义区别:spa
声明变量时使用Optional<T>而不是具体的Object,这句声明很是清楚地代表了这里发生变量的缺失是容许的。对象
2. 应用Optional的几种模式接口
建立Optional对象get
-- 声明一个空的Optionalit
Optional<Car> optCar = Optional.empty();
-- 依据一个非空值建立Optional
Optional<Car> optCar = Optional.of(car); //若是car是一个null,这段代码会当即抛出NullPointException,而不是等到试图访问car的属性值时才返回一个错误。
-- 可接受null的Optional(实现序列化的域模型时使用)
Optional<Car> optCar = Optional.ofNullable(car); //建立一个容许null值的Optional对象,若是car是null,那么获得的Optional对象就是个空对象
使用map从Optional对象中提取和转换值
public class Person { //有人有车,有人没车 private Optional<Car> car; public Optional<Car> getCar() { return car;} }
public class Car { //有的车有保险,有的车没有保险 private Optional<Insurance> insurance; public Optional<Insurance> getInsurance() { return insurance;} }
public class Insurance { //保险公司必定有名字,若是有保险公司没有名字则是出错状况 private String name; public String getName() { return name;} }
Optional<Insurance> optInsurance = Optional.ofNullable(insurance); Optional<String> name = optInsurance.map(Insurance::getName)
使用flatMap连接Optional对象
使用流时,flatMap方法接受一个函数做为参数,这个函数的返回值时另外一个流。这个方法会应用到流中的每个函数,最终造成一个新的流的流。可是flatMap会用流的内容替换每一个新生成的流。即,由方法生成的各个流会被合并或扁平化为一个单一的流。
Optional<Person> optPerson = Optional.of(person); Optional<String> name = optPerson.map(Person::getCar) .map(Car::getInsurance) //错误代码 .map(Insurance::getName)
getCar返回的是Optional<Car>类型的对象,因此第一个map获得的结果是Optional<Optional<Car>>类型的对象。所以他对getInsurance 的调用是非法的。不支持getInsurance方法。
使用flatMap会捋平两层结构的Optional为一个包含了Car的单层结构。
Optional<String> name = optPerson.flatMap(Person::getCar) .flatMap(Car::getInsurance) .map(Insurance::getName) .orElse(""Unknown); //若是Optional结果为空,设置默认值
默认行为及解引用Optional对象
-- get()是这些方法中最简单最不安全的方法。若是存在变量,他直接返回封装的变量值,不然抛出NoSuchElementException;
-- orElse(T other)容许你在Optional对象不包含值时提供一个默认值;
-- orElseGet(Supplier<? extends T> other)是orElse方法的延迟调用版,Supplier方法只有在Optional对象不含值时才执行调用。若是建立默认值是耗时费力的工做,应该采起这种方式,或你须要很是肯定某个方法仅在Optional为空时才调用,也能够考虑该方法(这种状况有严格的限制条件);
-- orElseThrow(Supplier<? extends X> exceptionalSupplier)和get方法很是相似,当Optional对象为空时都会抛出异常,但使用orElseThrow你能够定制但愿抛出的异常;
-- ifPresent(Consumer<? super T>)让你能在变量值存在时执行一个做为参数传入的方法,不然就不进行任何操做。
两个Optional对象组合
public Optional<Insurance> nullSafeFindCheapestInsurance(Optional<Person> person, Optional<Car> car) { return person.flatMap(p -> car.map(c -> findCheapestInsurance(p, c))); }
使用filter剔除特定的值
//找出年龄大于或等于minAge参数的Person所对应的保险公司列表 public String getCarInsuranceName(Optional<Person> person, int minAge) { return person.filter(p -> p.getAge() >= minAge) .flatMap(Person::getCar) .flatMap(Car::getInsurance) .map(Insurance::getName) .orElse("Unknown"); }
Optional和Stream接口有不少相似的方法。
Optional类的方法
方法 |
描述 |
empty |
返回一个空的Optional实例 |
filter |
若是值存在而且知足提供的谓词,就返回包含该值的Optional对象;不然返回一个空的Optional对象 |
flatMap |
若是值存在,就对该值执行提供的mapping函数调用,返回一个Optional类型的值,不然就返回一个空的Optional对象 |
get |
若是值存在,就将被Optional封装的值返回,不然抛出一个NoSunchElementException异常 |
ifPresent |
若是值存在,就执行使用该值的方法调用,不然什么也不作 |
isPresent |
若是值存在就返回true,不然返回false |
map |
若是值存在,就对该值执行提供提供的mapping函数调用 |
of |
将指定值用Optional封装以后返回,若是该值为null,则抛出一个NullPointException异常 |
ofNullable |
将指定值用Optional封装以后返回,若是该值为null,则返回一个空的Optional对象 |
orElse |
若是有值则将其返回,不然返回一个默认值 |
orElseGet |
若是有值则将其返回,不然返回一个由指定的Supplier接口生成的值 |
OrElseThrow |
若是有值则将其返回,不然抛出一个指定的Supplier接口生成的异常 |