一. 用Optional取代null
1. Optional类
java.util.Optional<T>是一个封装Optional值的类。
变量存在时,Optional类只是对类进行简单的封装。变量不存在时,缺失的值会被建模成一个“空”的Optional对象,由方法Optional.empty()返回。
Optional.empty()方法是一个静态工厂方法,它返回Optional类的特定单一实例。
使用Optional而不是null的一个非常重要而又实际的语义区别:
声明变量时使用Optional<T>而不是具体的Object,这句声明非常清楚地表明了这里发生变量的缺失是允许的。
2. 应用Optional的几种模式
创建Optional对象
-- 声明一个空的Optional
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接口生成的异常 |
共同学习,写下你的评论
评论加载中...
作者其他优质文章