前言

针对optional的操作,这篇博客进行简单的总结。

optional介绍

如果你作为Java程序员曾经遭遇过NullPointerException,请举起手。如果这是你最常遭遇的异常,请继续举手。非常可惜,这个时候,我们无法看到对方,但是我相信很多人的手这个时候是举着的。这句话是《Java 8 in action》一书中的原话,可以看出其实java中针对NPE的问题确实让吾等程序员很困惑。

基础实例:

需要处理一个拥有汽车保险嵌套信息

public class Person {

    private Car car;

    public Car getCar() {
        return car;
    }

    public void setCar(Car car) {
        this.car = car;
    }
}

public class Car {

    private Insurance insurance;

    public Insurance getInsurance() {
        return insurance;
    }

    public void setInsurance(Insurance insurance) {
        this.insurance = insurance;
    }
}

public class Insurance {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

如果要获取某个指定人员的保险名称,一般都会作出如下操作:

return person.getCar().getInsurance();

但是,但问题是,不是所有人都有车,即使有车也不是所有的车都有保险的啊,所以上述的代码NPE会高频的发生。为了避免NPE,我们有时候会有这样的代码:

public static String getInsuranceNameByMultiExit(Person person){
    if(person!=null){
        Car car=person.getCar();
        if(car!=null){
            Insurance insurance = car.getInsurance();
            if(insurance!=null){
                return insurance.getName();
            }
        }
    }
    return "Unknown";
}

 或者这样的代码:

public static String getInsuranceNameByMultiExit(Person person){
    final String defalutValue = "UNKNOW";
    if(null==person)
        return defalutValue;
    Car car = person.getCar();
    if(null==car)
        return defalutValue;
    Insurance insurance = car.getInsurance();
    if(insurance==null)
        return defalutValue;
    return insurance.getName();
}

 一堆的判空操作来避免NPE,显然有点无语。optional的出现就是优化这个问题

optional的使用

optional的创建

声明一个空的Optional

可以通过一个静态工厂方法Optional.empty,创建一个空的Optional,如下所示:

Optional<Insurance> emptyInsurance = Optional.<Insurance>empty();

 依据一个非空值创建Optional

Optional<Insurance> insurance = Optional.of(new Insurance());//如果为空的话,会抛出NPE

 Optional.of()的源码如下:

public static <T> Optional<T> of(T value) {
    return new Optional<>(value);
}

private Optional(T value) {
    this.value = Objects.requireNonNull(value);
}

public static <T> T requireNonNull(T obj) {
    if (obj == null)//可以看到,如果of中传递的是空,则这里会抛NPE
        throw new NullPointerException();
    return obj;
}

可接受null的optional

Optional<Object> o = Optional.ofNullable(null);//这里构建可以为空

 这个相当于前两者的结合。Optional.ofNullable的源码如下:

public static <T> Optional<T> ofNullable(T value) {
    return value == null ? empty() : of(value);
}

如果value为空,则返回默认的empty(),如果不为空,则调用of。 

Optional的get操作

普通的get

这个比较简单,这里直接上get的源码吧

public T get() {
    if (value == null) {
        throw new NoSuchElementException("No value present");
    }
    return value;
}

 普通的get操作,如果出现空,则直接抛出空指针的异常。

orElseGet和orElse

两者的简单实例:

Optional<Object> nullOptional = Optional.ofNullable(null);//这里构建可以为空
nullOptional.orElseGet(Insurance::new);
nullOptional.orElse(new Insurance());

 两者的源码如下:

public T orElseGet(Supplier<? extends T> other) {//这个为一个Supplier接口
    return value != null ? value : other.get();
}

public T orElse(T other) {//这个参数为一个具体的对象
    return value != null ? value : other;
}

可以看出,两者的区别就是参数不同。

orElseThrow

如果没有获取到Optional中的实例,则直接抛出一个异常。实例和源码如下:

nullOptional.orElseThrow(RuntimeException::new);
nullOptional.orElseThrow(() -> new RuntimeException("Not have reference"));

源码如下:

public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
    if (value != null) {
        return value;
    } else {
        throw exceptionSupplier.get();
    }
}

 isPresent和ifPresent

这个就更简单了,直接上源码

public boolean isPresent() {
    return value != null;
}

public void ifPresent(Consumer<? super T> consumer) {
    if (value != null)
        consumer.accept(value);
}

isPresent只是判断Optional中的value是否为空,ifPresent中,如果为空不做任何操作,如果不为空调用consumer的accept方法,这个consumer接口我们在Java8的第一篇博客中有过介绍。

Optional中的map操作和之前我们介绍的map操作的作用几乎类似,这里就不再赘述。下面看一个简单的综合实例。 

一个综合实例

1、将上述实例中的Person,Car中所持有的属性,修改成Optional类型,如下所示:

public class Person {

    private Optional<Car> car;

    public Optional<Car> getCar() {
        return car;
    }

    public void setCar(Optional<Car> car) {
        this.car = car;
    }
}

public class Car {

    private Optional<Insurance> insurance;

    public Optional<Insurance> getInsurance() {
        return insurance;
    }

    public void setInsurance(Optional<Insurance> insurance) {
        this.insurance = insurance;
    }
}

随后,我们重构一下获取客户保险的实例:

public static String getInsuranceNameOptional(Person person) {
    return Optional.ofNullable(person)
            .flatMap(Person::getCar)
            .flatMap(Car::getInsurance)
            .map(Insurance::getName).orElse("UnKnown");
}

 说明:这里用到了flatMap而不是map方法,这个需要说明一下,从源码来看

map方法的源码:

public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
    Objects.requireNonNull(mapper);
    if (!isPresent())
        return empty();
    else {
        return Optional.ofNullable(mapper.apply(value));//可以看到,这里内部包装了一下
    }
}

如果调用map方法,由于返回值是Optional<U>,而U又本身是Optional类型,如果用Optional.ofNullable(person).map(Person::getCar)这样返回的并不是Optional<Car>而是Optional<Optional<Car>>。这样明显是不能进行下一步的

flatMap的源码如下:

public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
    Objects.requireNonNull(mapper);
    if (!isPresent())
        return empty();
    else {
        return Objects.requireNonNull(mapper.apply(value));
    }
}

可以看出flatMap就是针对Optional<Object>的参数进行了一部分拆分。针对这两者如果读者有心可以直接阅读原著中的实例,不过我个人认为《Java8 in action》一书中对这两者通过实例图片的形式来解释似乎并不太好。

总结

本篇博客总结了Optional的操作,从源码级别分析了各个函数,以及使用中的注意事项,其实Java8并没有想象中的那么可怕,慢慢学习总会有所收获。