天天看點

[Google Guava] 1.1-使用和避免null

輕率地使用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會讓查找操作的語義更清晰。

如果你想把null作為map中某條目的值,更好的辦法是 不把這一條目放到map中,而是單獨維護一個”值為null的鍵集合” (null keys)。map 中對應某個鍵的值是null,和map中沒有對應某個鍵的值,是非常容易混淆的兩種情況。是以,最好把值為null的鍵分離開,并且仔細想想,null值的鍵在你的項目中到底表達了什麼語義。

如果你需要在清單中使用null——并且這個清單的資料是稀疏的,使用map<integer, e>可能會更高效,并且更準确地符合你的潛在需求。

此外,考慮一下使用自然的null對象——特殊值。舉例來說,為某個enum類型增加特殊的枚舉值表示null,比如java.math.roundingmode就定義了一個枚舉值unnecessary,它表示一種不做任何舍入操作的模式,用這種模式做舍入操作會直接抛出異常。

如果你真的需要使用null值,但是null值不能和guava中的集合實作一起工作,你隻能選擇其他實作。比如,用jdk中的collections.unmodifiablelist替代guava的immutablelist

optional

大多數情況下,開發人員使用null表明的是某種缺失情形:可能是已經有一個預設值,或沒有值,或找不到值。例如,map.get傳回null就表示找不到給定鍵對應的值。

<code>1</code>

<code>optional&lt;integer&gt; possible = optional.of(</code><code>5</code><code>);</code>

<code>2</code>

<code>3</code>

<code>possible.ispresent(); </code><code>// returns true</code>

<code>4</code>

<code>5</code>

<code>possible.get(); </code><code>// returns 5</code>

optional無意直接模拟其他程式設計環境中的”可選” or “可能”語義,但它們的确有相似之處。

optional最常用的一些操作被羅列如下:

<b>建立optional執行個體(以下都是靜态方法):</b>

<a href="http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/base/optional.html#of(t)">optional.of(t)</a>

建立指定引用的optional執行個體,若引用為null則快速失敗

<a href="http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/base/optional.html#absent()">optional.absent()</a>

建立引用缺失的optional執行個體

<a href="http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/base/optional.html#fromnullable(t)">optional.fromnullable(t)</a>

建立指定引用的optional執行個體,若引用為null則表示缺失

<b>用optional執行個體查詢引用(以下都是非靜态方法):</b>

<a href="http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/base/optional.html#ispresent()">boolean ispresent()</a>

如果optional包含非null的引用(引用存在),傳回true

<a href="http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/base/optional.html#get()">t get()</a>

傳回optional所包含的引用,若引用缺失,則抛出java.lang.illegalstateexception

<a href="http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/base/optional.html#or(t)">t or(t)</a>

傳回optional所包含的引用,若引用缺失,傳回指定的值

<a href="http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/base/optional.html#ornull()">t ornull()</a>

傳回optional所包含的引用,若引用缺失,傳回null

<a href="http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/base/optional.html#asset()">set&lt;t&gt; asset()</a>

傳回optional所包含引用的單例不可變集,如果引用存在,傳回一個隻有單一進制素的集合,如果引用缺失,傳回一個空集合。

<b>使用</b><b>optional</b><b>的意義在哪兒?</b>

使用optional除了賦予null語義,增加了可讀性,最大的優點在于它是一種傻瓜式的防護。optional迫使你積極思考引用缺失的情況,因為你必須顯式地從optional擷取引用。直接使用null很容易讓人忘掉某些情形,盡管findbugs可以幫助查找null相關的問題,但是我們還是認為它并不能準确地定位問題根源。

如同輸入參數,方法的傳回值也可能是null。和其他人一樣,你絕對很可能會忘記别人寫的方法method(a,b)會傳回一個null,就好像當你實作method(a,b)時,也很可能忘記輸入參數a可以為null。将方法的傳回類型指定為optional,也可以迫使調用者思考傳回的引用缺失的情形。

其他處理null的便利方法