Guava 指南個人翻譯 —— 注意NULL!!

Using and avoiding null 使用和避免 ‘NULL’

“Null sucks.(Null 就是狗屎)” -[Doug Lea(譯註:JCP成員,紐約州立大學計算機系教授,JCP成員,java.concurrent包作者)]

“I call it my billion-dollar mistake(Null引用:代價十億美元的錯誤).” - [Sir C. A. R. Hoare(譯註:託尼.霍爾, 圖靈獎得主)]

十分隨意的使用 null 會導致很多驚人的 bug 產生. 我們在研究 Google 代碼庫之後發現:
幾乎 95% 的 集合類不接受一個 null 作爲其中的值, 所以我們認爲, 相比與默默的使用 null
並且容忍它對我們的傷害, 不如使用快速失敗操作拒絕 null 對開發者們來的更有幫助.

此外, null 具有使人十分難受的模糊語義, 如果 null 作爲一個返回值, 它很少具有十分清晰的含義.
舉個栗子: Map.get(key) 返回一個 null 值, 它可以表示這個 map 中是空的, 或者是 map
中沒有 key 對應的值. null 可以表示失敗, 可以表示成功, 甚至是表示任何情況.
可是如果我們使用除了 null 之外的其他值, 將會使語義更加的清晰明確.

同時還有着另一種情況, 在一些情況下: null 有着合適和正確的使用場景.
在內存使用以及運行速度方面, null 是非常廉價、低消耗的, 同時, 它也是數組中不可避免的存在.
但是在基於底層庫的應用級別的代碼中, null 通常是導致含糊語義以及疑難bug的罪魁禍首,
就像我們之前討論過的 Map.get 返回 null 值的含義問題. 最關鍵的是, null 並沒有定義 null 值是什麼含義.

基於以上原因, Guava 的很多工具類都定義了對 null 值的快速失敗, 同時,
除非工具類本身對 NULL 定義了確定的含義(值), 否則不允許 null 值被使用.
並且, Guava 也提供了大量的方法, 在你有需要的時候, 能幫助你使用特定的值來代替結果集中的 NULL.

Specific Cases 特殊情況

不要嘗試着將 null 作爲 Set 中的一個值或者 Map 中的一個鍵! 在查找操作中,
使用一個特殊的確定的值來代替 null 會使語義毫無驚喜 (less surprising) 的清晰起來.

如果你想使用 null 作爲一個 Map 中的值, 不如把它們整理出來單獨作爲一個集合來進行維護,
比如將你的 Set 分爲兩個, 不含 null 和只含 null 的. 在一個 Map 中, ‘一個確定的鍵對應了的值是NULL’
‘Map中確定的鍵沒有與之對應的值’ 是十分容易混淆的. 所以, 最好是將值爲 null 的鍵從這個 map 中分離出來,
並且需要你仔細想想:null 在你的應用程序中到底代表着什麼含義.

如果你想在一個十分"稀疏"的列表中使用"NULL", 還不如用一個 Map<Integer, E> 來的更好一點,
Map 可能會有更高效的性能, 並能滿足您應用程序中潛在的需求.

我們還需要思考一個特殊情況, 我們可能需要一個特殊的的 “null值對象”, 並不總是能用到,但是有時候我們真的需要有。
舉個栗子, 比如有個枚舉類需要添加一個特殊的枚舉值爲 null, 就像 java.math.RoundingMode 中提供了一個 UNNECESSARY 來表示 “不做任何取整的操作,
如果有任何取整的行爲( 譯註:除非計算結果爲整數,不然都拋出異常 ), 就快速拋出一個異常”.

如果你真的需要一個空值, 可是 Guava 中的"非空"集合類卻不能夠滿足你的要求,
那麼你應該使用集合類另外的實現, 比如使用 JDK 中的 Collections.unmodifiableList(Lists.newArrayList())
來代替 Guava 的 ImmutableList.

Optional 對象

在大多數的情況中, 程序開發者們使用 null 來表示一種 “缺失” 的情境 ————
在某個地方可能表示默認的值, 也可能是表示那個地方沒有值, 或者是那個值找不到了。
舉個簡單的例子:就像 Map.get 方法,當它找不到 key 所對應的 value 的時候, 就會返回一個 null.

Optional<T> 是使用一個 “非空” 的值來代替一個 “可爲空” 的 T 類型引用的一種方法,
一個 Optional 實例可能包含着一個非空的 T 類型引用(這種情況我們稱之爲 引用存在 ),
也可能什麼都不包含(我們稱之爲 引用缺失), 總之, 就是不會出現引用爲 null 的情況.

Optional<Integer> possible = Optional.of(5);
possible.isPresent(); // 對象是否存在? 返回 true
possible.get(); // 返回 5

Optional 並非刻意的模擬其他編程語言下已經存在的 “option” 或者 “maybe” 的情況,
但是總會有那麼一些相似.

我們這裏給出了一些常用的 Optional 操作.

Making an Optional 構建一個 Optional

這列出 Optional 的一些靜態方法.

Method Description 描述
Optional.of(T) 創建指定引用 T 的 Optional 對象, 如果該引用爲 null 則快速失敗.
Optional.absent() 創建一個 引用缺失 的 Optional 對象.
Optional.fromNullable(T) 創建一個指定引用 T 的 Optional 對象, T 可能爲 null, 如果爲 null, 則生成一個 引用缺失 的 Optional 對象.

Optional 的查詢方法

這些方法都不是靜態的.

Method Description 描述
boolean isPresent() 如果這個 Optional 對象包含的是 非空 引用, 返回 true.
T get() 返回這個 Optional 所包含的 T 類型引用, 這個引用必須 存在, 否則拋出一個 IllegalStateException 異常.
T or(T) 返回這個 Optional 所包含的 T 類型引用, 如果引用缺失, 返回一個指定的默認值.
T orNull() 返回這個 Optional 所包含的 T 類型引用, 如果引用缺失, 返回一個 null. 這是fromNullable(T) 方法的逆操作.
Set<T> asSet() 返回包含於這個 Optional 的不可變單例集合, 如果引用存在, 返回只有單一元素的集合, 如果引用缺失, 返回一個空的不可變集合

Optional 提供了更多有用的工具方法, 瀏覽 Javadoc 以獲得更多信息…

What’s the point? 意義是什麼?

一方面, Optional 爲 null 賦予確定的語義增強了可閱讀性, 另一方面, Optional最大的優點可以看做是提供了 傻瓜式 的防護.
Optional 使你將注意力集中在思考可能導致 引用缺失 的情況, 因爲你必須 顯式 的從 Optional 中獲取引用.
null 很容易使人忘記或者忽略掉一些細節, 儘管你可以通過 FindBugs 來找到那些相關的bug, 但是我們並不認爲這能準確定位到問題的根源.

與方法入參可能爲 null 一樣, 你的方法返回值也可能具有不那麼 現實 含義(可能爲 Null).
你(或者其他人)可能會忘記別人給你提供的方法 method(a, b) 方法可能返回一個 null, 同樣的,
你也會在你的方法 method(a, b) 中忽略掉入參 a 也可能爲 null 的問題. 使用 Optional 作爲你方法的返回值,
迫使你必須考慮到各種可能引起 引用缺失 的情況, 直到考慮全面才能使你的代碼通過編譯.

Convenience methods 一些有用的方法

當你想要使用 null 來代替一些默認值得話, 請使用 MoreObjects.firstNonNull(T, T),
就像方法名所表示的那樣, 如果這兩者值都是 null, 將會拋出一個 NullPointerException異常.
而如果使用了一個 Opintion, 那就不會有這樣的問題出現, 他將非常完美的代替 null. 比如 Optional.fromNullable(first).or(second).

我們提供了一些方法去處理那些可能爲 null 的字符串類型的數據. 通過方法名, 我們能清晰地知道這個方法的作用是什麼:

需要特別強調的是, 我們提供的這些方法主要是用於改善那些將 nullempty String (空字符串) 混淆使用的API.
當你寫出那些 null 字符串empty 字符串 混淆的代碼的時候, 就是我們 Guava 團隊哭泣的時候.
(如果 null 字符串 和 empty 字符串 明顯代表着不同含義, 我們建議您不如直接將他們分開來,
而如果您仍要堅持將他們混爲一談的話, 那這真是個悲傷的故事)

參考資料:
https://github.com/google/guava/wiki/UsingAndAvoidingNullExplained
牛津大辭典

後記:我將所有內容都發布在 Github 上,您可以加入我們,也可以提出問題共同討論,下面是我Github 的項目地址:【guava-jch】
~如果能點個 star 就更好了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章