前言
空指针是我们最常见也最讨厌的异常,为了防止空指针异常,你不得在代码里写大量的非空判断。
Java 8引入了一个新的Optional类。用于避免空指针的出现,也无需在写大量的if(obj!=null)这样的判断了,前提是你得将数据用Optional装着,它就是一个包裹着对象的容器。
都说没有遇到过空指针异常的程序员不是Java程序员,null确实引发过很多问题。Java 8中引入了一个叫做java.util.Optional的新类可以避免null引起的诸多问题。
我们看看一个null引用能导致哪些危害。首先创建一个类Computer,结构如下图所示:

当我们调用如下代码会怎样?
String version = computer.getSoundcard().getUSB().getVersion();
上述代码看似是没有问题的,但是很多计算机(比如,树莓派)其实是没有声卡的,那么调用getSoundcard()方法可定会抛出空指针异常了。
一个常规的但是不好的的方法是返回一个null引用来表示计算机没有声卡,但是这就意味着会对一个空引调用getUSB()方法,显然会在程序运行过程中抛出控制异常,从而导致程序停止运行。想想一下,当你的程序在客户端电脑上运行时,突然出现这种错是多尴尬的一件事?
伟大计算机科学Tony Hoare曾经写到:"我认为null引用从1965年被创造出来导致了十亿美元的损失。当初使用null引用对我最大的诱惑就是它实现起来方便。"
那么该怎么避免在程序运行时会出现空指针异常呢?你需要保持警惕,并且不断检查可能出现空指针的情况,就像下面这样:
String version = "UNKNOWN";if(computer != null) { Soundcard soundcard = computer.getSoundcard(); if(soundcard != null){ USB usb = soundcard.getUSB(); if(usb != null){ version = usb.getVersion(); } } }然而,你可以看到上述代码有太多的null检查,整个代码结构变得非常丑陋。但是我们又不得不通过这样的判断来确保系统运行时不会出现空指针。如果在我们的业务代码中出现大量的这种空引用判断简直让人恼火,也导致我们代码的可读性会很差。
如果你忘记检查要给值是否为空,null引用也是存在很大的潜在问题。这篇文章我将证明使用null引用作为值不存在的表示是不好的方法。我们需要一个更好的表示值不存在的模型,而不是再使用null引用。
Java 8引入了一个新类叫做java.util.Optional<T> ,这个类的设计的灵感来源于Haskell语言和Scala语言。这个类可以包含了一个任意值,像下面图和代码表示的那样。你可以把Optional看做是一个有可能包含了值的值,如果Optional不包含值那么它就是空的,下图那样。

public class Computer { private Optional<Soundcard> soundcard; public Optional<Soundcard> getSoundcard() { ... } ...}public class Soundcard { private Optional<USB> usb; public Optional<USB> getUSB() { ... }}public class USB{ public String getVersion(){ ... }}上述代码展现了一台计算机有可能包换一个声卡(声卡是有可能存在也有可能不存在)。声卡也是有可能包含一个USB端口的。这是一种改善方法,该模型可以更加清晰的反映一个被给定的值是可以不存在的。
但是该怎么处理Optional<Soundcard>这个对象呢?毕竟,你想要获取的是USB的端口号。很简单,Optional类包含了一些方法来处理值是否存在的状况。和null引用相比Optional类迫使你在你要做值是否相关处理,从而避免了空指针异常。
需要说明的是Optional类并不是要取代null引用。相反地,是为了让设计的API更容易被理解,当你看到一个函数的签名时,你就可以判断要传递给这个函数的值是不是有可能不存在。这就促使你要打开Optional类来处理确实值的状况了。
采用Optional模式