Java NullPointerException-如何在Java中有效處理空指針

Java NullPointerException是未經檢查的異常,而且進行了擴展RuntimeExceptionNullPointerException不會強制咱們使用catch塊來處理它。html

1.爲何在代碼中出現NullPointerException

NullPointerException是代碼中您嘗試訪問/修改還沒有初始化的對象的狀況。從本質上講,它意味着對象引用變量沒有指向任何地方,而且不指向任何內容或爲「 null 」。一個拋出空指針異常的示例Java程序。java

package com.howtodoinjava.demo.npe;
 
public class SampleNPE
{
    public static void main(String[] args)
    {
       String s = null ;
       System.out.println( s.toString() );   // 's' is un-initialized and is null
    }
}

 

2. Java NullPointerException一般發生的常見位置

好吧,因爲各類緣由NullPointerException可能會出如今代碼中的任何位置,可是我根據本身的經驗準備了最常出現的地點清單。express

  1. 在未初始化的對象上調用方法
  2. 方法中傳遞的參數是 null
  3. 調用toString()對象的方法是null
  4. if不檢查null相等性的狀況下比較塊中的對象屬性
  5. 對於像Spring這樣的依賴注入的框架來講,配置不正確
  6. synchronized在一個對象上使用null
  7. 連接的語句,即單個語句中的多個方法調用

這不是詳盡的清單。還有其餘幾個地方和緣由。若是您還能夠回憶起其餘任何內容,請發表評論。它也會幫助其餘人(初學者)。apache

 

3.避免Java NullPointerException的最佳方法

3.1。三元運算符

若是不爲null,則運算符將得出左側的值,不然將評估右側。它具備以下語法:api

布爾表達式?value1:value2;

若是expression計算爲true,則整個表達式將返回value1,不然返回value2。它更像if-else構造,可是更有效和更具表現力。爲了防止NullPointerException(NPE),請像如下代碼同樣使用此運算符:安全

字符串str =(參數==空)「 NA」:參數;

3.2。使用Apache Commons StringUtils進行字符串操做

Apache commons lang是用於各類操做之王的幾個實用程序類的集合。其中之一是StringUtils.java使用StringUtils.isNotEmpty()驗證做爲參數傳遞的字符串是否爲空或空字符串。若是不爲null或爲空;而後進一步使用它。oracle

其餘相似的方法是StringUtils。IsEmpty()和StringUtils.equals()。他們在javadocs中聲稱,若是StringUtils.isNotBlank()拋出NPE,則API中存在錯誤。框架

if (StringUtils.isNotEmpty(obj.getvalue())){
     String s = obj.getvalue();
     ....
}

3.3。很早檢查方法參數是否爲空

您應該始終將輸入驗證置於方法的開頭,以使其他代碼沒必要處理輸入錯誤的可能性。所以,若是有人傳遞空值,那麼事情將在堆棧中早點破裂,而不是在較深的位置(根本問題很難識別)中破裂。ide

在大多數狀況下,針對快速故障行爲是一個不錯的選擇。this

3.4。考慮原始而不是對象

當對象引用指向無內容時,將發生空問題。所以,儘量多地使用原語始終是安全的,由於它們不會受到空引用的影響。全部原語都必須附加一些默認值,所以請小心。

3.5。仔細考慮連接方法調用

雖然鏈式語句很容易在代碼中查看,但它們不是NPE友好的。一條分散在多行中的語句將爲您提供堆棧跟蹤中第一行的行號,不管它出如今何處。

  ref.method1().method2().method3().methods4();

這種鏈式語句將僅打印「 行號xyz中發生了NullPointerException」。調試這樣的代碼確實很難。避免此類呼叫。

3.6。使用String.valueOf()而不是toString()

若是必須打印任何對象的字符串表示形式,請不要使用object.toString()。這是NPE的很是軟的目標。而是使用String.valueOf(object)。
即便object在第二種方法中爲null,它也不會給出異常,而且將輸出null來輸出流。

3.7。避免從方法中返回null

避免NPE的一個很棒的技巧是返回空字符串或空集合,而不是返回null。在您的應用程序中一致地執行此操做。您會注意到,若是這樣作,則不須要進行大量的空檢查。

例如:

List<string> data = null ;
 
@SuppressWarnings ( "unchecked" )
public List getDataDemo()
{
    if (data == null )
       return Collections.EMPTY_LIST; //Returns unmodifiable list
    return data;
}

使用上述方法的用戶即便錯過了空檢查,也不會看到難看的NPE。

3.8。不鼓勵傳遞空參數

我已經看到一些方法聲明,其中方法須要兩個或多個參數。若是參數之一做爲null傳遞,則方法以某種不一樣的方式起做用。避免這種狀況。

相反,您應該定義兩種方法;一個帶有單個參數,第二個帶有兩個參數。強制傳遞參數。當您在方法內部編寫應用程序邏輯時,這頗有幫助,由於您能夠確保方法參數不會爲null。所以,您不會放置沒必要要的假設和斷言。

3.9。在「安全」非空字符串上調用String.equals(String)

代替在下面的代碼中編寫字符串比較

public class SampleNPE {
    public void demoEqualData(String param) {
       if (param.equals( "check me" )) {
          // some code
       }
    }
}

像這樣寫上面的代碼。即便參數做爲null傳遞,這也不會在NPE中引發。

public class SampleNPE {
    public void demoEqualData(String param) {
       if ( "check me" .equals(param)) // Do like this
       {
          // some code
       }
    }
}

 

4.可用的NullPointerException安全操做

4.1。運算符實例

instanceof運算符是NPE安全的。所以,instanceof null老是返回false。它不會致使NullPointerException。若是您記住這一事實,則能夠消除混亂的條件代碼。

// Unnecessary code
if (data != null &amp;&amp; data instanceof InterestingData) {
}
 
// Less code. Better!!
if (data instanceof InterestingData) {
}

4.2。訪問類的靜態成員

若是您要處理靜態變量或靜態方法,則即便您的引用變量指向null,也不會獲得null指針異常,由於靜態變量和方法調用是在編譯時根據類名綁定的,而且與對象無關

MyObject obj = null ;
String attrib = obj.staticAttribute; //no NullPointerException because staticAttribute is static variable defined in class MyObject

5.若是必須在某些地方容許NullPointerException怎麼辦

Joshua bloch在有效的Java中說:「能夠說,全部錯誤的方法調用均可以歸結爲非法論點或非法狀態,可是其餘例外一般用於某些種類的非法論據和狀態。若是調用者在某個參數中傳遞了null,而該參數禁止使用null值,則約定NullPointerException將拋出而不是IllegalArgumentException

所以,若是必須NullPointerException在代碼的某些地方容許使用,則請確保使它們比一般具備更多的信息性看下面的例子:

package com.howtodoinjava.demo.npe;
 
public class SampleNPE {
    public static void main(String[] args) {
       // call one method at a time
       doSomething( null );
       doSomethingElse( null );
    }
 
    private static String doSomething( final String param) {
       System.out.println(param.toString());
       return "I am done !!" ;
    }
 
    private static String doSomethingElse( final String param) {
       if (param == null ) {
          throw new NullPointerException(
                " :: Parameter 'param' was null inside method 'doSomething'." );
       }
       System.out.println(param.toString());
       return "I am done !!" ;
    }
}

這兩個方法調用的輸出是這樣的:

Exception in thread "main" java.lang.NullPointerException
  at com.howtodoinjava.demo.npe.SampleNPE.doSomething(SampleNPE.java: 14 )
  at com.howtodoinjava.demo.npe.SampleNPE.main(SampleNPE.java: 8 )
 
Exception in thread "main" java.lang.NullPointerException:  :: Parameter 'param' was null inside method 'doSomething' .
  at com.howtodoinjava.demo.npe.SampleNPE.doSomethingElse(SampleNPE.java: 21 )
  at com.howtodoinjava.demo.npe.SampleNPE.main(SampleNPE.java: 8 )

顯然,第二個堆棧跟蹤更有用,而且使調試容易。

相關文章
相關標籤/搜索