什么是JAVA中的空指針(NullPointerExceptions),如何避免程序中的空指針?

什么是JAVA中的空指針(NullPointerExceptions),如何避免程序中的空指針?

空指針異??梢哉f是java中最常見的異常之一了,你對它又了解多少呢?

什么是空指針

眾所周知,JAVA中有兩大類類型:基本類型和引用類型?;绢愋涂梢杂删幾g器保證使用前必須初始化為一個有效值(但是不一定是業(yè)務(wù)的有效值),使用它不會導(dǎo)致空指針異常;而引用類型可以被初始化為一個特殊的值null,說明該引用未引用任何值。
當(dāng)使用一個null對象的屬性,或調(diào)用其方法時,會觸發(fā)空指針異常(NullPointerExceptions)。下面是官方文檔給出的拋出異常的情況:

  • Calling the instance method of a null object.(調(diào)用null的實例方法)
  • Accessing or modifying the field of a null object.(調(diào)用或者修改null的屬性)
  • Taking the length of null as if it were an array.(獲取null數(shù)組的長度)
  • Accessing or modifying the slots of null as if it were an array.(訪問或修改null數(shù)組中的元素)
  • Throwing null as if it were a Throwable value.(常規(guī)拋出null異常)

調(diào)用null的實例方法 / 調(diào)用或者修改null的屬性

可以看下面的代碼示例:

// 類型定義
class SomeClass{
    // 僅作演示,盡量不要定義public的屬性。
    public int someField;
    public void someMethod(){
    }
}

SomeClass someClass = null;
someClass.someMethod();
someClass.someField = 10;

輸出:

Exception in thread "main" java.lang.NullPointerException
    ...

SomeClass someClass = null;聲明了一個引用someClass并賦值為null,someClass.someMethod();嘗試調(diào)用null的實例方法(java8+也可能通過 someclass::somemethod 語法來調(diào)用),會拋出空指針異常;someClass.someField = 10;修改null的屬性,也會拋出空指針異常。

獲取null數(shù)組的長度 / 訪問或修改null數(shù)組中的元素

可以看下面的代碼示例:

int[] nullArray = null;
int length = nullArray.length;
nullArray[0] = 10;

輸出:

// 獲取長度空指針
Exception in thread "main" java.lang.NullPointerException
    at ...

int[] nullArray = null;聲明了一個引用nullArray并賦值為null,int length = nullArray.length;獲取null數(shù)組的長度,會拋出空指針異常;nullArray[0] = 10;修改null數(shù)組中的元素,也會拋出空指針異常。

常規(guī)拋出null異常

出了"被動"觸發(fā)空指針異常外,我們還可以手動拋出空指針異常,比如這樣:throw new NullPointerException("null!");

編程中一些空指針異常觸發(fā)場景以及規(guī)避方法

方法參數(shù)中的空指針

方法參數(shù)中的空指針觸發(fā)場景

當(dāng)我們對外開放一個方法時,方法的入?yún)⒕陀锌赡軙徽{(diào)用方傳入null,比如下列方法:

int someMethod(Object someObj){
    someObj.xxx();
    return 0;
}

如果調(diào)用方傳入null:int res = someMethod(null);,那么在下面就會導(dǎo)致空指針異常了。

方法參數(shù)中的空指針防范方法

對于這類對外開放的(public/protected)方法來說,保護(hù)自己就很重要,防范方法一般是提前檢查入?yún)⑹欠駶M足要求,如果不滿足要求則拋出異常,可以通過類庫中的Objects.requireNonNull()來完成,比如:

int someMethod(Object someObj){
    Objects.requireNonNull(someObj, "someObj must not be null");
    someObj.xxx();
}

這一條當(dāng)然不只適用于我們自己編寫程序的時候,在使用第三方的類庫時,也要注意使用的類庫的方法參數(shù)是否支持null,對方也許粗心大意未處理這類異常,自己要多加小心。

方法返回值中的空指針異常

方法返回值空指針的觸發(fā)場景

使用別人的程序時,除了要注意入?yún)⒁酝?,返回值也要額外留意,確認(rèn)該方法的返回值是否會返回null,防止造成不必要的麻煩。比如:

Integer getArrayLength(int[] num){
    if (num == null){
        return null;
    } else{
        return num.length;
    }
}

上述方法會返回傳入的數(shù)組長度,當(dāng)傳入數(shù)組為空時,會返回null。如果調(diào)用時,傳入了一個null數(shù)組,并且嘗試用它返回的值進(jìn)行加減,那么就會導(dǎo)致空指針異常了,如下所示:

int[] array = null;
......很長的代碼之后
Integer length = getArrayLength(array);
// 空指針!
int res = length + 10;
.....

這里的空指針看起來沒有那么明顯,實際上,在getArrayLength返回一個裝箱類型Integer的時候,這個異常就埋下了伏筆,在int res = length + 10;時,返回的length被自動拆箱,導(dǎo)致了空指針異常。
這也是一種比較罕見的情況,但是出現(xiàn)這類問題可能會有漫長的debug等著我們了。
當(dāng)返回值是裝箱類型的時候,務(wù)必要特別留意。

除了上面這種以外,還有一類obj.getXX().getXXX()..的調(diào)用方法需要額外小心,一旦出現(xiàn)問題很難定位,最好別用。

方法返回值空指針的防范方法

對于方法的設(shè)計者來說,盡量不要返回null,返回數(shù)組和集合時,盡量返回一個空數(shù)組new SomeObj[0]或者是空集合Collections.emptyXXX(),如果是因為入?yún)⒋嬖趩栴}無法正常返回,及時拋出參數(shù)異常,不要默默返回null;遇到必須返回null的時候,可以返回Optional<T>。 盡量不要返回裝箱類型,除非迫不得已。

對于方法的使用方來說,最好確定方法會不會返回null并做對應(yīng)處理。實在無法確定的,最好自己判斷一下空指針。遇到裝箱返回值的,要警惕自動拆箱。

語句塊中的空指針

這類空指針比較少見,語句塊可以是for/switch/synchronized等。下面依次舉例:

// for語句塊中,iterable為null會導(dǎo)致空指針
for (element : iterable) 
// switch語句塊中,表達(dá)式xxx結(jié)果為空會導(dǎo)致空指針
switch (xxx) { ... }
// synchronized語句塊中,傳入null會導(dǎo)致空指針異常
synchronized (someNullReference) { ... }

防范方法主要是提前檢查。

一些其他的防范方法

string比較時,常量在前面

見代碼:

if ("some string".equals(xxx))

使用SonarLint插件(idea)

SonarLint插件不止可以檢查空指針,還可以檢查很多的常見編程問題。idea中可以直接在插件市場搜索安裝。
提示: idea中代碼被標(biāo)注成背景是黃色時,通常說明可能存在問題,可以把鼠標(biāo)挪上去查看詳情。

jdk14中的空指針異常增強(qiáng)

jdk14中添加了對于空指針異常友好的提示,便于開發(fā)者快速定位空指針的對象。示例代碼:

int[] nullArray = null;
nullArray[0] = 10;

輸出如下:

Exception in thread "main" java.lang.NullPointerException: Cannot store to int array because "nullArray" is null

可以看到比之前的提示友好了很多,可以直接定位問題所在。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容