Doug Lea 說,「Null 真糟糕。」 java
當Sir C. A. R. Hoare 使用了null引用後說,」使用它致使了十億美金的錯誤。」 git
輕率地使用null可能會致使不少使人驚愕的問題。經過學習Google底層代碼庫,咱們發現95%的集合類不接受null值做爲元素。咱們認爲, 相比默默地接受null,使用快速失敗操做拒絕null值對開發者更有幫助。
編程
此外,Null的含糊語義讓人很不舒服。Null不多能夠明確地表示某種語義,例如,Map.get(key)返回Null時,可能表示map中的值是null,亦或map中沒有key對應的值。Null能夠表示失敗、成功或幾乎任何狀況。使用Null之外的特定值,會讓你的邏輯描述變得更清晰。 數組
Null確實也有合適和正確的使用場景,如在性能和速度方面Null是廉價的,並且在對象數組中,出現Null也是沒法避免的。但相對於底層庫來講,在應用級別的代碼中,Null每每是致使混亂,疑難問題和模糊語義的元兇,就如同咱們舉過的Map.get(key)的例子。最關鍵的是,Null自己沒有定義它表達的意思。 工具
鑑於這些緣由,不少Guava工具類對Null值都採用快速失敗操做,除非工具類自己提供了針對Null值的因變措施。此外,Guava還提供了不少工具類,讓你更方便地用特定值替換Null值。 性能
具體案例 學習
不要在Set中使用null,或者把null做爲map的鍵值。使用特殊值表明null會讓查找操做的語義更清晰。 google
若是你想把null做爲map中某條目的值,更好的辦法是 不把這一條目放到map中,而是單獨維護一個」值爲null的鍵集合」 (null keys)。Map 中對應某個鍵的值是null,和map中沒有對應某個鍵的值,是很是容易混淆的兩種狀況。所以,最好把值爲null的鍵分離開,而且仔細想一想,null值的鍵在你的項目中到底表達了什麼語義。 spa
若是你須要在列表中使用null——而且這個列表的數據是稀疏的,使用Map<Integer, E>可能會更高效,而且更準確地符合你的潛在需求。
此外,考慮一下使用天然的null對象——特殊值。舉例來講,爲某個enum類型增長特殊的枚舉值表示null,好比java.math.RoundingMode就定義了一個枚舉值UNNECESSARY,它表示一種不作任何舍入操做的模式,用這種模式作舍入操做會直接拋出異常。
若是你真的須要使用null值,可是null值不能和Guava中的集合實現一塊兒工做,你只能選擇其餘實現。好比,用JDK中的Collections.unmodifiableList替代Guava的ImmutableList
Optional
大多數狀況下,開發人員使用null代表的是某種缺失情形:多是已經有一個默認值,或沒有值,或找不到值。例如,Map.get返回null就表示找不到給定鍵對應的值。
Guava用Optional<T>表示可能爲null的T類型引用。一個Optional實例可能包含非null的引用(咱們稱之爲引用存在),也可能什麼也不包括(稱之爲引用缺失)。它從不說包含的是null值,而是用存在或缺失來表示。但Optional從不會包含null值引用。
1 | Optional<Integer> possible = Optional.of(5); |
2 |
3 | possible.isPresent(); // returns true |
4 |
5 | possible.get(); // returns 5 |
Optional無心直接模擬其餘編程環境中的」可選」 or 「可能」語義,但它們的確有類似之處。
Optional最經常使用的一些操做被羅列以下:
建立Optional實例(如下都是靜態方法):
Optional.of(T) | 建立指定引用的Optional實例,若引用爲null則快速失敗 |
Optional.absent() | 建立引用缺失的Optional實例 |
Optional.fromNullable(T) | 建立指定引用的Optional實例,若引用爲null則表示缺失 |
用Optional實例查詢引用(如下都是非靜態方法):
boolean isPresent() | 若是Optional包含非null的引用(引用存在),返回true |
T get() | 返回Optional所包含的引用,若引用缺失,則拋出java.lang.IllegalStateException |
T or(T) | 返回Optional所包含的引用,若引用缺失,返回指定的值 |
T orNull() | 返回Optional所包含的引用,若引用缺失,返回null |
Set<T> asSet() | 返回Optional所包含引用的單例不可變集,若是引用存在,返回一個只有單一元素的集合,若是引用缺失,返回一個空集合。 |
使用Optional的意義在哪兒?
使用Optional除了賦予null語義,增長了可讀性,最大的優勢在於它是一種傻瓜式的防禦。Optional迫使你積極思考引用缺失的狀況,由於你必須顯式地從Optional獲取引用。直接使用null很容易讓人忘掉某些情形,儘管FindBugs能夠幫助查找null相關的問題,可是咱們仍是認爲它並不能準確地定位問題根源。
如同輸入參數,方法的返回值也多是null。和其餘人同樣,你絕對極可能會忘記別人寫的方法method(a,b)會返回一個null,就好像當你實現method(a,b)時,也極可能忘記輸入參數a能夠爲null。將方法的返回類型指定爲Optional,也能夠迫使調用者思考返回的引用缺失的情形。
其餘處理null的便利方法
當你須要用一個默認值來替換可能的null,請使用Objects.firstNonNull(T, T) 方法。若是兩個值都是null,該方法會拋出NullPointerException。Optional也是一個比較好的替代方案,例如:Optional.of(first).or(second).
還有其它一些方法專門處理null或空字符串:emptyToNull(String),nullToEmpty(String),isNullOrEmpty(String)。咱們想要強調的是,這些方法主要用來與混淆null/空的API進行交互。當每次你寫下混淆null/空的代碼時,Guava團隊都淚流滿面。(好的作法是積極地把null和空區分開,以表示不一樣的含義,在代碼中把null和空同等對待是一種使人不安的壞味道。