在Java中如何避免“!=null”式的判空語句?

c6g3 9年前發布 | 26K 次閱讀 Java Java開發

問題描述:

我整天都是在跟Java打交道。我在Java開發中最常用的一段代碼就是用object != null在使用對象之前判斷是否為空。這么做是為了避免NullPointerException。但是我發現這樣檢測代碼實在是太丑了,而且及其不可讀。

那有沒有一種優雅的替代方法呢?

問題補充:

再清晰化一下我的問題,我是在強調在使用對象的屬性或者方法之前,確保它不為空的重要性,就像下面這段代碼一樣:

if (someobject != null) {
    someobject.doCalc();
}

這么些我是為了避免拋NullPointerException異常,我不知道這個對象是不是空的。正由于這些判空代碼,導致我的代碼血花四濺,相當慘不忍睹。

最佳解答:

對于我來說,這就是一個初級開發者走向中級開發者過程中有時候都會碰到的合理問題:他們不知道也不太信任自己所使用的約定,并且過度的去檢查空值情況。另外,當他們寫代碼的時候,總是會讓方法去返回一些值,因此就可以由方法調用方去檢查空值了。

換句話說,有兩種情況會出現判空語句:

  • null返回值按找約定是正常的返回值
  • null返回值不是正常的返回值
  • </ul>

    第二種情況很簡單。可以使用assert來判斷或者是允許程序報錯(即拋NullPointerException)。斷言是一個被充分利用的Java特性,在1.4版本中加入了這個特性。語法如下:

    assert *<condition>*

    或者是

    assert *<condition>* : *<object>*

    object的toString()輸出會被包括在錯誤信息中。

    當判斷條件為false的時候assert語句就會拋出Error(AssertionError)錯誤。在默認情況下,Java虛擬機是不會理會斷言語句的。當需要使用此特性的時候可以給JVM虛擬機傳入-ea參數來啟用它。同時也可以針對單個的Java類或者是包來使用斷言特性。這就意味著可以在開發測試的過程中來使用斷言驗證代碼,而在生產環境就關閉這個特性,盡管我已經測試顯示斷言功能并不會對應用程序產生任何影響。

    這個案例中不使用斷言是可以的,因為代碼本身就是會報錯的,就像假如你使用斷言之后一定會拋出Error錯誤一樣。用和不用的區別就是可以盡早的去發現錯誤,用更有意義,更加豐富的信息來描述這個錯誤,這樣你就可以幫助你弄清楚為什么會發生這種錯誤(假如這種錯誤你確實不想它發生)。

    第一種情況就要難解釋一點了。如果你對你調用的代碼沒有控制權的話,你就慘了。如果null返回值是正常的話,那你就必須去檢查它了。

    如果可以控制你調用代碼(當然常常還是有控制權的),那就是另一回事兒了。還是盡量的不去使用null返回值。對于返回集合的方法很簡單,只需要返回空的集合就可以了,而不是null。

    對于返回值不是集合的方法,就要麻煩一點了。假如碰到下面的情況:

    public interface Action {
      void doSomething();
    }

    public interface Parser { Action findAction(String userInput); }</pre>

    Parse接口從標準輸入中接受指令,并去執行一些操作,可能會去用這個接口實現一個命令行工具。那現在就有個約定當沒找到合適的操作指令時,就返回空值。那這兒就得去驗空值了。

    一種可選辦法就是不使用空返回值,而是空對象模式

    public class MyParser implements Parser {
      private static Action DO_NOTHING = new Action() {
        public void doSomething() { / do nothing / }
      };

    public Action findAction(String userInput) { // ... if ( / we can't find any actions / ) { return DO_NOTHING; } } }</pre>

    來對比下下面這兩種:

    Parser parser = ParserFactory.getParser();
    if (parser == null) {
      // now what?
      // 這兒當然得空值判斷一下啊,這兒根本就不應該出現空值
    }
    Action action = parser.findAction(someInput);
    if (action == null) {
      // do nothing
    } else {
      action.doSomething();
    }
    ParserFactory.getParser().findAction(someInput).doSomething();

    明顯下面這種寫法更加簡明清晰。

    其實在findAction()方法中直接拋出更加有意義的錯誤信息是完全可以的。特別是你在依賴用戶輸入的應用中。對于findAction()方法來說拋出一個帶有說明的異常要比光禿禿的拋出一個NullPointerException要好的多。

    try{
        ParserFactory.getParser().findAction(someInput).doSomething();
    } catch(ActionNotFoundException anfe) {
        userConsole.err(anfe.getMessage());
    }

    要是你覺得使用try/catch機制比較丑的話,那就給用戶比較有意義的反饋。

    public Action findAction(final String userInput){
        /* Code to return requested Action if found */
        return new Action(){
            public void doSomething(){
                userConsole.err("Action not found: "+userInput);
            }
        }
    }

    首發:譯鄰

    原文鏈接: Stack Overflow 翻譯: ImportNew.com - strongme
    譯文鏈接: http://www.importnew.com/13002.html


 本文由用戶 c6g3 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!