由@NotNull 註解引出的關於Java空指針的控制

Java 小技巧和在java應用避免NullPonintException的最佳方法

在java應用程序中,一個NullPonintException(空指針異常)是最好解決(問題)的方法。同時,空指針也是寫健壯的順暢運行的代碼的關鍵。“預防好過治療”這句話也同樣適用於令人不爽的NullPonintException。通過應用防禦性的編碼技術和在遵守多個部分之間的約定,你可以再很大程度上避免NullPointException。下面的這些java小技巧可以最小化像!=null這種檢查的代碼。作爲經驗豐富的java程序猿,你可能意識到這些技術的某部分項目當中使用它。但是對於大學一年級學生和中級開發者,這是一個很好的學習機會。

這是一些很容易學會的簡單技術,但是對於代碼質量和健壯性來說確實很重要。以我的經驗,僅是第一個小技巧就已經對改進代碼質量具有很大的作用了。

1)在已經的String(字符串)調用 equal()和 equalsingnoreCase()而不是未知的對象

通常在已經的非空字符串在調用equals()。因爲equal()方法是對稱的,調用a.equal()是同等於調用b.equal(),和這就是爲什麼很多部注意對象a和b,如果空的一邊被調用會到導致空指針。

Object unknownObject = null;

//wrong way - may cause NullPointerException
if(unknownObject.equals(“knownObject”)){
System.err.println(“This may result in NullPointerException if unknownObject is null”);
}

//right way - avoid NullPointerException even if unknownObject is null
if(“knownObject”.equals(unknownObject)){
System.err.println(“better coding avoided NullPointerException”);
}

這是最重要的避免NullPointException的java技巧,但是結果會是極大的改進,因爲equal()是一個很普遍的方法。

2)在兩者返回相同結果的時候偏向使用valueOf()而非toString()

因爲空對象調用toString()時會拋出NullPointException。如果我們可以通過調用value()得到相同的值的話,就應該使用valueOf()。這樣會傳遞會一個空值。特別是在像Integer,Float,Double或者BigDecimla之類的包裝類的情況下。

BigDecimal bd = getPrice();
System.out.println(String.valueOf(bd)); //doesn’t throw NPE
System.out.println(bd.toString()); //throws “Exception in thread “main” java.lang.NullPointerException”

如果你不確定你所使用的對象是否是空的時候,請使用這個JAVA技巧

3)使用空安全方法(null safe method)或者類庫

現在有很多已經爲你做了null檢查的開源組件出現。其中一個最爲普遍的就是Apache的StringUtils。你可以使用StringUtils.isBlank(),isNumberic(),isWhiteSpace()和其他工具一些不用擔心NullPointException方法。

System.out.println(StringUtils.isEmpty(null));
System.out.println(StringUtils.isBlank(null));
System.out.println(StringUtils.isNumeric(null));
System.out.println(StringUtils.isAllUpperCase(null));

Output:
true
true
false
false

但在作出任何結論之前,不要忘記閱讀關於Null安全方法和類的文檔。這是另一個java最佳操練,這不會要求你付出非常多的努力,但會讓你獲得很大的進步。

4)避免用返回空的collection或者空的array來代替從方法中返回Null

這個java技巧也是在Joshua Bloch的《Effective Java》所提及的。這本書也是一個提高JAVA編碼能力的一個來源。通過返回一個空的collection或者一個空的array可以確定像size(),length()這種基礎的調用不會拋出NullPointException。Collection類能夠提供方便的空的List,Set和Map,(這些)有Collections.EMPTY_LIST, Collections.EMPTY_SET和 Collections.EMPTY_MAP這些能夠被使用的(靜態變量)。

代碼如下;

public List getOrders(Customer customer){

List result = Collections.EMPTY_LIST;

return result;

}

注意:使用Collections.emptyList()生成的List不支持add方法

調用Add會拋出unsupportedException,在以後要返回一個空的List,並還需要後續操作時,不能使用Collections.emptyList()方法,看文檔發現,List的實現類都有自己的實現,而返回的EmptyList的實現沒有實現add(int index, E element方法,使用了
AbstractList.add(int index, E element){
    throw new UnsupportedOperationException();
}

類似地你可以使用Collections.EMPTY_LIST, Collections.EMPTY_SET和 Collections.EMPTY_MAP來代替返回Null。

5)使用@NotNull和@Nullable註釋

當寫你可以定義關於約定可空性(Nullability),要通過使用像@NotNull和@Nullable類似的註釋提示這個方法是否爲空安全(null safe)。現代的編譯器,IDE和其他工具可以讀出這個註釋來幫你做一個空檢查或者告訴你是否需要空檢查。IntelliJIDE和findbugs 已經支持這種註釋。這些註釋也是JSR 305(譯者注:可以理解爲java的標準)的一部分。通過看到@NotNull和@Nullable,程序猿可以自己決定是否去進行空檢查。順便說下,對於JAVA程序猿來說,這是新的最好的實踐,儘管需要一點時間去適應。

6)遵循約定和定義合理的默認值

在java領域,一個最佳的避免空指針的方法之一就是和定下約定和遵守約定。大部分的NullPointException發生原因就是使用了一個不完整的信息或者並沒有被提供所有的依賴信息來創建對象。如果你不允許創建不完整的對象和否定任何這種要求,你可以預防很多一段時間之後發生的NullPointException。如果對象被允許創建,那麼你應該設定合理的默認值。例如,一個Employee(僱員)對象不可以在沒有Id和Name屬性的情況下被創建,但可以有一個可供選擇的pghone number(電話號碼)。如果Employee沒有phone number,那麼就用返回一個0來代替返回一個空值。但是這種處理必須非常小心地處理對空值的檢查而不是檢查非法輸入。同樣要注意,定義可以使空值的或者不可以空值的時候,提醒調用者作出被告知的決定。失敗之後的選擇或者接受空值也是一個你需要重視的重要設計。

7)數據庫對空值的約束

如果你使用數據庫去存儲你的域對象(demain object),例如:Customer、Orders等等,那麼你應該定義一些在數據庫對空值的約束。因爲數據庫可以要求獲得從多個來源來的數據,在數據庫中擁有對空值的檢查將會確保數據的完整性。在數據庫中保留對空值約束的約束也是會讓你減少在JAVA中減少空檢查的代碼。當從數據庫中取出一個對象是,你可以確保那些屬性可以是空而那些屬性不可以使空,這將會讓那些空檢查的代碼最小化。

8)使用空對象模式

這是另外一個在JAVA裏面避免NullPointException的方法。如果一個方法返回一個對象,哪個調用者要遍歷這個對象,哪個調用者就要使用一些類似Collection.iterator()的方法去返回iterator。如果調用者沒有任何的上述的這些方法,那麼有可能返回的是空對象而不是空(null)。空對象是一個特別的對象,它在不同的上下文中有不同的含義。像這些返回Contrainter或者Conllection類型的方法的情況中,裏面爲空的對象(Empty object)應該被使用而不是返回空。

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