用過Java的童鞋應該有很深的體會,Java中經常會出現NPE(NullPointException,空指針)異常,如果不處理好是一件非常頭疼的事情,而為了處理NPE需要增加很多代碼來避免,造成代碼汙染,有潔癖的童鞋可能會受不了哇。在Java8之前,這類人就喜歡用Google公司著名的Guava庫的Optional類來處理NPE問題,使我們的Java代碼更乾淨,也許是受到Guava啟發,Java8也引入了Optional,連名字都一模一樣。
一、引子
我們先來看一段代碼:
public String getGender(Cat cat) {
if(null == cat) {
return "未知";
}
if(cat.getGender() == 0) {
return "公的";
}
return "母的";
}
可以看出,為了處理NPE我們寫了很多防禦性的代碼來避免。
二、Optional如何優雅處理NPE
public String getGender(Cat cat) {
return Optional.ofNullable(cat).map(c -> c.getGender() == 0 ? "公的" : "母的").orElse("未知");
}
簡潔、優雅有木有。
三、Optional的實現原理
通過查看Optional源碼我們可以看出,Optional的狗子函數是私有的,因此不能直接通過new 來創建Optional對象,它有三個靜態方法:
public staticOptional of(T value) {
return new Optional<>(value);
}
public staticOptional ofNullable(T value) {
return value == null ? empty() : of(value);
}
public staticOptional empty() {
@SuppressWarnings("unchecked")
Optionalt = (Optional ) EMPTY;
return t;
}
三個方法都好理解,唯一要多一句嘴的就是of和ofNullable的區別,從實現上可以知道,of表明Optional包含的對象是絕對不允許為空的,如果為空就會爆NPE,而ofNullable則表示允許為空,最終是不是空交給用戶去處理。一般情況下ofNullable可以滿足我們絕大部分使用場景。那潔癖的童鞋該問了,有了ofNullable為啥還要of?按我的理解,我認為of的使用場景在於明確必須不為空的情況下,如果為空一定要爆NPE,例如我們創建對象時可以這麼寫:
Optional.of(new Cat());
這時,我們就必須保證new Cat()不為空,如果為空說明內存溢出了,必須馬上爆出異常通知。
Optional還有幾個方法做一下解釋:
(1)get
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
當用Optional.get()時,若包含對象為空,將會拋出NoSuchElementException異常。
(2)isPresent
public boolean isPresent() {
return value != null;
}
該方法只是做了次判空操作,我覺得在實際應用中是沒有什麼價值的,因為它只是把判空操作封裝成一個方法,僅此而已
(3)ifPresent
public void ifPresent(Consumer super T> consumer) {
if (value != null)
consumer.accept(value);
}
該方法接受一個函數式接口Consumer,Consumer與Function類似,只是Function有返回處理結果,而Consumer沒有。由於ifPresent內部已經做過判空操作,因此我們可以直接使用無需擔心NPE問題。
(4)filter
public Optionalfilter(Predicate super T> predicate) {
Objects.requireNonNull(predicate);
if (!isPresent())
return this;
else
return predicate.test(value) ? this : empty();
}
我們可以通過filter方法對內容進行過濾,例如我們可以過濾出貓齡大於5的貓
public static void filterAge(Cat cat)
{
Optional.ofNullable(cat).filter( c -> c.getAge() > 5).ifPresent(c -> System.out.println("The cat age is more than 5."));
}
(5)map
public Optional map(Function super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Optional.ofNullable(mapper.apply(value));
}
}
map方法用於映射,即通過某種規則將對象映射為另外一個對象,上面我們寫的getGender就用了map方法。
(6)orElse、orElseGet、orElseThrow
// 該方法允許Optional處理當內容為空時的替代值,或默認值
public T orElse(T other) {
return value != null ? value : other;
}
// 該方法允許通過一個Supplier函數接口返回一個其他值
public T orElseGet(Supplier extends T> other) {
return value != null ? value : other.get();
}
// 該方法是當為空時拋出異常
publicT orElseThrow(Supplier extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}
掌握了Optional,我們也可以寫出簡潔優雅的Java代碼。
閱讀更多 鷹眼世界 的文章