关于Optional的好文:Optional是个好东西,你会用么?(全面深度解析)
下面这段摘自阿里JAVA编程规范:
防止NPE,是程序员的基本修养,注意NPE产生的场景:
1) 返回类型为基本数据类型,return包装数据类型的对象时,自动拆箱有可能产生NPE。 反例:public int f() { return Integer对象}, 如果为null,自动解箱抛NPE。
2) 数据库的查询结果可能为null。
3) 集合里的元素即使isNotEmpty,取出的数据元素也可能为null。
4) 远程调用返回对象时,一律要求进行空指针判断,防止NPE。
5) 对于Session中获取的数据,建议进行NPE检查,避免空指针。
6) 级联调用obj.getA().getB().getC();一连串调用,易产生NPE。
正例:使用JDK8的Optional类来防止NPE问题。
Optional相比if(obj==null)有什么区别呢,到底对程序能够带来什么改变?
基本介绍
打开源码Optional的源码,会发现和Integer等包装类很相似,Optional只有一个私有的非静态变量:T value。实际上,Optional也只是一个包装类,所有的方法都是在这个value上做操作,也没什么其他的花样。下面是Optional基本的方法。
//创新value为=null的Optional
public static<T> Optional<T> empty();
//创建内容为value的Optional,value不能为空
public static <T> Optional<T> of(T value);
//同上,value可以为空
public static <T> Optional<T> ofNullable(T value);
//判断value是否为空
public boolean isPresent();
//获取value
public T get();
//如果值不为空,执行Consumer的accept()
public void ifPresent(Consumer<? super T> consumer);
//过滤符合条件的value
public Optional<T> filter(Predicate<? super T> predicate);
//将一个Optional的value应用Function得到新的OPtional
public<U> Optional<U> map(Function<? super T, ? extends U> mapper);
//将一个Optional的value应用Function得到新的OPtional,和map方法的区别主要function的返值不同
public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper);
//获取返回值,如果返回值为空则返回other
public T orElse(T other);
//获取返回值,如果返回值为空则调用other的get()
public T orElseGet(Supplier<? extends T> other);
//和上面的方法大致相同,不同点是Supplier的返回值必须是Throwable的子类并且在Optional的value为null时抛出该throwable
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier);
应用场景
从上面的方法中,一些列的map、flatmap、Predicate、Function、Consumer、Supplier等(相同的内容也出现在了java的Stream、guava、rxJava等场景中,虽然java、guava、rxJava对这些都没有相互间的继承关系,自成一体,但他们的功能都是一致的,谁抄的谁就不考证了)无不昭示着Optional是为了函数式编程而生的,所以使用Optional的正确姿势是将它用于函数式编程,而不是用它去实现简单的空指针判断,比如下面的蠢驴式用法:
if(obj==null) {
return null;
}
return obj;
//这种修改除了加了一层包装消耗了性能之外没有任何作用
if(!Optional.ofNullable(obj).isPresent()) {
return null;
}
return obj;
正确优雅的姿势是下面的这种改动。
Person person=new Person("Tom");
Person header=person.getSon().getSon().getSon();
Person person=new Person("Tom");
Person person1=new Person("none");
Optional<Person> optionalPerson=Optional.ofNullable(person);
Person header=optionalPerson.map(Person::getSon).
map(Person::getSon).
map(Person::getSon).
orElse(person1);
链式的调用极易产生空指针而且还需定位空指针的位置,在使用了函数式编程的组合调用之后即没有产生数个if(person==null)的判断又处理了任何一个环节出现问题的返回值问题。
所以如果不是在链式调用或者需要对结果进行一系列处理的情况而仅仅是一个==null的判断就不要使用Optional来浪费时间。