JDK8 Optional类

451 阅读3分钟

JDK8 Optional类

作为JDK8新特性之一,Optinal这个容器类,在工作中经常用到,也是非常好用的一个类,让你的判断空变得优雅;

首先来看看官方在Optional类上的注释

A container object which may or may not contain a non-null value.If a value is present, {@code isPresent()} will return {@code true} and{@code get()} will return the value. 一个有可能包含一个非空值的容器,如果该值不为空(isPresent方法可以判断),将通过get()方法返回该值

Additional methods that depend on the presence or absence of a contained value are provided, such as {@linkorElse(java.lang.Object) orElse()} (return a default value if value not present) and {@link ifPresent(java.util.function.Consumer) ifPresent()} (execute a block of code if the value is present).另外容器提供了额外的方法用于处理容器内的值存在或者不存在的情况,例如orElse()

蹩脚的英文翻译完毕,下面描述下Optional的类作用:

1.可以用于解决由于返回值为null导致的NullPointException问题;
2.将非空判断的方式''标准化''

废话不多说,下面上代码:

代码原型-案例摘自<<Java8实战>>

public class Person {
    private Car car;
    public Car getCar() { return car; }
}
public class Car {
    private Insurance insurance;
    public Insurance getInsurance() { return insurance; }
}
public class Insurance {
    private String name;
    public String getName() { return name; }
}
//那么,下面这段代码存在怎样的问题呢?
public String getCarInsuranceName(Person person) {
    return person.getCar().getInsurance().getName();
}

显然在上述代码的

    getCarInsuranceName(Personperson)

方法中,由于person是否为null不确定性,有可能导致person在调用getCar()导致NullPointerException的发生,亦或由于getCar()方法的值为null,以及getInsurance()方法为null导致的方法调用出现NullPointerException的问题

传统的解决方式:

1.过多的判断 例如

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

2.过多的退出语句

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

以上两种解决方式是不是特点繁琐,明明同样的工作,却反复做了三次,代码的可读性变差,你愿意写这样的代码吗?这个时候Optional类登场了 那么使用Optional类之后的做法是:

public String getCarInsuranceName(Person person) {
    Optional.ofNullable(person).flatMap(Person::getCar).flatMap(Car::getInsurance).map(Insurance::getName).orElse("unKnown")
}

在上述改造中Optional.ofNullable()方法将传入的参数person包装了一番,即允许person为空,此时看看该方法的源码

Returns an {@code Optional} describing the specified value, if non-null, otherwise returns an empty {@code Optional}.返回该容器内的非空值的容器对象,若为空,则返回调用empty()方法返回null值对应的容器对象

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

该方法返回一个Optional类容器对象,然后在获取getCar(),getInsurance(),getName()的方法中如果任一方法返回值为null,那么就将返回unKnown这个值,巧妙的避免了null值调用,而是用容器对象调用;

例子结束,那么我们再看看Optional类中其他实用的方法

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

get()方法用于获取容器内的value值,在value值不存在的时候将会报出异常,那么这时候有个问题了,依前述所言,Optional类不应该是解决null值问题的吗,怎么会允许这种情况发生呢?我们继续看第二个方法isPersent()

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

isPersent()方法用于判断容器内是的值是否为null,返回值为Boolean类型, 通常的做法为isPresent()和get()方法连用

    private  String  test() {
       String name="null or not null?";
       Optional<String> optional = Optional.of(name);
       if (optional.isPresent()){
           throw  new RuntimeException("结果异常");
       }
       return  optional.get();
   }

这种做法在实际开发中中,dao层查询数据库返回结果给service层时常用该方法;

3.orElse()
    Person person = userService.findById(5);
   return  Optional.ofNullable(person).filter(p->p.getAge()>0).orElse(new Person(0,"default"));

过滤查询结果的age属性大于0的对象,此时这里虽然没有做null值判断,但是ofNullable()方法会自动进行处理,从而不会导致空指针问题