使用Optional避免空指针
Optional各方法
《Java 8 Features Tutorial – The ULTIMATE Guide》中给出了两个简单的例子,我们从这两个例子入手来简单了解一下Optional容器的使用。
示例一:
1 public static void main(String[] args) { 2 Optional< String > fullName = Optional.ofNullable( null ); 3 System.out.println( "Full Name is set? " + fullName.isPresent() ); 4 System.out.println( "Full Name: " + fullName.orElseGet( () -> "[none]" ) ); 5 System.out.println( fullName.map( s -> "Hey " + s + "!" ).orElse( "Hey Stranger!" ) ); 6 }
运行结果:
Full Name is set? false Full Name: [none] Hey Stranger!
说明:
ifPresent()方法当Optional实例的值非空时返回true,否则返回false;
orElseGet()方法当Optional包含非空值时返回该值,否则通过接收的function生成一个默认的;
map()方法转换当前Optional的值,并返回一个新的Optional实例;
orElse()方法与orElseGet方法相似,不同的是orElse()直接返回传入的默认值。
示例二:修改示例一,使其生成一个非空值的Optional实例
1 Optional< String > firstName = Optional.of( "Tom" ); 2 System.out.println( "First Name is set? " + firstName.isPresent() ); 3 System.out.println( "First Name: " + firstName.orElseGet( () -> "[none]" ) ); 4 System.out.println( firstName.map( s -> "Hey " + s + "!" ).orElse( "Hey Stranger!" ) );
输出结果:
First Name is set? true First Name: Tom Hey Tom!
可以清晰地看出与示例一的区别。这不但简洁了我们的代码,而且使我们的代码更便于阅读。
下面看一下例子中使用到的几个方法的源码:
1)、of
1 public static <T> Optional<T> of(T value) { 2 return new Optional<>(value); 3}
2)、isPresent
1 public boolean isPresent() { 2 return value != null; 3 }
3)、orElseGet
1 public T orElseGet(Supplier<? extends T> other) { 2 return value != null ? value : other.get(); 3 }
4)、orElse
1 public T orElse(T other) { 2 return value != null ? value : other; 3 }
思考: 调用一个方法得到了返回值却不能直接将返回值作为参数去调用别的方法。
原来解决方案: 我们首先要判断这个返回值是否为null,只有在非空的前提下才能将其作为其他方法的参数。这正是一些类似Guava的外部API试图解决的问题。
一些JVM编程语言比如Scala、Ceylon等已经将对在核心API中解决了这个问题。
新版本的Java,比如Java 8引入了一个新的Optional类。Optional类的Javadoc描述如下:
这是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。
在我们日常开发过程中不可避免地会遇到空指针问题,在以前,出现空指针问题,我们通常需要进行调试等方式才能最终定位到具体位置,尤其是在分布式系统服务之间的调用,问题更难定位。在使用Optional后,我们可以将接受到的参数对象进行包装,比如,订单服务要调用商品服务的一个接口,并将商品信息通过参数传入,这时候,传入的商品参数可能直接传入的就是null,这时,商品方法可以使用Optional.of(T)对传入的对象进行包装,如果T为空,则会直接抛出空指针异常,我们看到异常信息就能立即知道发生空指针的原因是参数T为空;或者,当传入的参数为空时,我们可以使用Optional.orElse()或Optional.orElseGet()方法生成一个默认的实例,再进行后续的操作。