1. Optional 类概述
空指针异常(NullPointerExceptions
)是 Java 最常见的异常之一,一直以来都困扰着 Java 程序员。一方面,程序员不得不在代码中写很多null
的检查逻辑,让代码看起来非常臃肿;另一方面,由于其属于运行时异常,是非常难以预判的。
为了预防空指针异常,Google
的Guava
项目率先引入了Optional
类,通过使用检查空值的方式来防止代码污染,受到Guava
项目的启发,随后在Java 8
中也引入了Optional
类。
Optional 类位于Java.util
包下,是一个可以为 null
的容器对象,如果值存在则isPresent()
方法会返回 true
,调用 get()
方法会返回该对象,可以有效避免空指针异常。下面我们来学习如何实例化这个类,以及这个类下提供了哪些常用方法。
2. 创建 Optional 对象
查看 Java.util.Optional
类源码,可以发现其构造方法是私有的,因此不能通过new
关键字来实例化:
我们可以通过如下几种方法,来创建Optional 对象:
Optional.of(T t)
:创建一个 Optional 对象,参数t
必须非空;Optional.empty()
:创建一个空的Optional
实例;Optional.ofNullable(T t)
:创建一个Optional
对象,参数t
可以为null
。
实例如下:
运行结果:
- 1
- 2
- 3
3. 常用方法
Optional<T>
类提供了如下常用方法:
booean isPresent()
:判断是否包换对象;void ifPresent(Consumer<? super T> consumer)
:如果有值,就执行 Consumer 接口的实现代码,并且该值会作为参数传递给它;T get()
:如果调用对象包含值,返回该值,否则抛出异常;T orElse(T other)
:如果有值则将其返回,否则返回指定的other
对象;T orElseGet(Supplier<? extends T other>)
:如果有值则将其返回,否则返回由Supplier
接口实现提供的对象;T orElseThrow(Supplier<? extends X> exceptionSupplier)
:如果有值则将其返回,否则抛出由Supplier
接口实现提供的异常。
知道了如何创建Optional
对象和常用方法,我们下面结合具体实例来看一下,Optional
类是如何避免空指针异常的。
请查看如下实例,其在运行时会发生空指针异常:
运行结果:
- 1
- 2
- 3
实例中,由于在实例化Goods
类时,我们没有给其下面的Category
类型的属性category
赋值,它就为 null
,在运行时, null.getName()
就会抛出空指针异常。同理,如果goods
实例为null
,那么null.getCategory()
也会抛出空指针异常。
在没有使用Optional
类的情况下,想要优化代码,就不得不改写getGoodsCategoryName()
方法:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
这也就是我们上面说的null
检查逻辑代码,此处有两层if
嵌套,如果有更深层次的级联属性,就要嵌套更多的层级。
下面我们将Optional
类引入实例代码:
运行结果:
- 1
实例中,我们使用Optional
类的 ofNullable(T t)
方法分别包装了goods
对象及其级联属性category
对象,允许对象为空,然后又调用了其ofElse(T t)
方法保证了对象一定非空。这样,空指针异常就被我们优雅地规避掉了。
4. 对于空指针异常的改进
Java 14 对于空指针异常有了一些改进,它提供了更明确异常堆栈打印信息,JVM 将精确地确定那个变量是null
,不过空指针异常依然无法避免。明确的异常堆栈信息,能够帮助开发者快速定位错误发生的位置。
5. 小结
通过本小节的学习,我们知道了 Optional
类主要用于应对 Java 中的空指针异常,它是一个可以为 null
的容器对象,我们可以通过Optional
类下的几个静态方法来创建对象。另外,我们也结合实例介绍了如何使用Optional
类来规避空指针异常,实例中还有很多其他没用到的 API,希望大家可以自己研习。