前言
针对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并没有想象中的那么可怕,慢慢学习总会有所收获。