詳解Java中NullPointerException的處理方法
一. 簡(jiǎn)介
你要問,Java中哪個(gè)異常最有名,那就不得不說NullPointerException!
NullPointerException,空指針異常,簡(jiǎn)稱為NPE。這對(duì)Java程序員來說,可以說是一個(gè)無人不知、無人不曉的異常了!空指針異常往往是由于程序員沒有考慮到變量或者對(duì)象的值可能為null,或者沒有對(duì)null值進(jìn)行判斷導(dǎo)致的。所以當(dāng)我們?cè)噲D訪問null對(duì)象或者是對(duì)null對(duì)象進(jìn)行操作時(shí),就會(huì)拋出NullPointerException異常。
NullPointerException異常在運(yùn)行時(shí)被拋出,如果不加以處理,會(huì)導(dǎo)致程序的中斷或者崩潰,因此我們?cè)诰帉慗ava程序時(shí),要格外注意避免空指針異常的發(fā)生。
二. 產(chǎn)生原因
之所以會(huì)出現(xiàn)NullPointerException空指針異常,最根本的原因只有一個(gè),那就是”對(duì)象為空“ ,這和很多單身狗的毛病一樣。也就是說,當(dāng)一個(gè)對(duì)象為null時(shí),你還非得調(diào)用該對(duì)象的方法或字段,此時(shí)JVM就會(huì)產(chǎn)生NullPointerException,例如:
public static void main(String[] args) { String s = null; System.out.println(s.toUpperCase()); }
當(dāng)上面這段代碼運(yùn)行時(shí),肯定會(huì)產(chǎn)生空指針異常,因?yàn)閷?duì)象”s“是null。也就是我們沒有給該對(duì)象初始化賦值,它就是一個(gè)空殼子,你還非要使用它,這時(shí)就會(huì)出事。
三. 典型情況
雖然我們現(xiàn)在已經(jīng)知道引發(fā)空指針異常的原因了,但為了讓大家避免這種常見的異常,還是想給大家列舉幾個(gè)會(huì)引發(fā)空指針異常的典型情況。
3.1 對(duì)空對(duì)象調(diào)用方法或訪問屬性
當(dāng)一個(gè)對(duì)象為null時(shí),它就沒有任何屬性和方法,如果我們?cè)谶@個(gè)空對(duì)象上調(diào)用方法或訪問屬性,就會(huì)引發(fā)空指針異常。例如:
String str = null; int length = str.length(); // 會(huì)拋出空指針異常
3.2 數(shù)組元素為null
在Java中,數(shù)組中的元素也可能會(huì)為null。如果我們?cè)谝粋€(gè)null數(shù)組元素上調(diào)用方法或訪問屬性,同樣會(huì)拋出空指針異常。例如:
String[] strs = new String[3]; strs[0] = "Hello"; strs[1] = null; int length = strs[1].length(); // 會(huì)拋出空指針異常
3.3 參數(shù)為null
在調(diào)用方法時(shí),如果參數(shù)為null,而方法內(nèi)部卻需要使用這個(gè)參數(shù),也會(huì)拋出空指針異常。例如:
public void printString(String str) { System.out.println(str.length()); } String str = null; printString(str); // 會(huì)拋出空指針異常
四. 解決辦法
為了避免空指針異常的發(fā)生,我們需要加強(qiáng)對(duì)變量和對(duì)象的判斷,如果發(fā)現(xiàn)其值為null,就需要及早進(jìn)行處理,例如設(shè)置默認(rèn)值或者拋出異常。我們要知道,NullPointerException其實(shí)是一種代碼邏輯錯(cuò)誤,遇到NullPointerException,要遵循”早暴露、早修復(fù)“的原則,不要使用catch語句來隱藏這種編碼錯(cuò)誤! 比如下面這樣的代碼就不行:
// 錯(cuò)誤示例: 捕獲NullPointerException try { transferMoney(from, to, amount); } catch (NullPointerException e) { //不要去捕獲空指針異常! }
接下來給大家列舉幾個(gè)常用的避免空指針異常的方法。
4.1 使用條件判斷語句
通過判斷變量是否為null,可以避免空指針異常的發(fā)生。例如:
String str = null; if (str != null) { int length = str.length(); }
4.2 使用對(duì)象初始化語句
我們?cè)谑褂脤?duì)象之前,確保要對(duì)該對(duì)象進(jìn)行初始化,這樣就可以保證對(duì)象不為null。例如:
String str = ""; int length = str.length();
我們?cè)诰帉憳I(yè)務(wù)邏輯時(shí),使用空字符串""表示未填寫,而不要用默認(rèn)的null,""空串要比null安全得多,這可以避免很多NullPointerException。
4.3 使用Objects.requireNonNull()方法
Objects.requireNonNull()方法可以判斷參數(shù)是否為null,如果是null,則會(huì)拋出NullPointerException異常。例如:
String str = null; Objects.requireNonNull(str, "str不能為空"); // 會(huì)拋出NullPointerException異常
4.4 返回空數(shù)組
如果我們使用數(shù)組時(shí),某個(gè)數(shù)組沒有數(shù)據(jù),此時(shí)可以返回一個(gè)元素為空的數(shù)組,但是不要返回null,比如:
public String[] getData(String item) { if (getItem(item) == 0) { // 返回空數(shù)組而不是null: return new String[0]; } ... }
這樣調(diào)用方就不用檢查結(jié)果是否為null。
4.5 使用Optional
Optional是Java 8中引入的一個(gè)非常有用的類,用于解決null值問題。它是一個(gè)容器對(duì)象,可能包含非空值或空值,主要目的是減少代碼中的空指針異常,當(dāng)調(diào)用方一定要判斷某個(gè)對(duì)象是否為null時(shí),就可以考慮使用Optional。接下來給大家編寫一個(gè)簡(jiǎn)單的Optional案例。
import java.io.IOException; import java.util.Optional; /** * @author 一一哥Sun */ public class Demo13 { public static void main(String[] args) throws IOException { String str="一一哥"; //創(chuàng)建一個(gè)包含非空值的Optional對(duì)象。如果傳入的值為null,則會(huì)拋出NullPointerException異常。 Optional<String> optional = Optional.of(str); if(optional.isPresent()) { String value = optional.get(); System.out.println("value="+value); }else { System.out.println("字符串為空"); } //ofNullable方法 String name = null; //Optional.ofNullable靜態(tài)工廠方法,創(chuàng)建一個(gè)包含指定值的Optional對(duì)象,如果傳入的值為null,則返回一個(gè)空的Optional對(duì)象 Optional<String> optionalName = Optional.ofNullable(name); String orElse = optionalName.orElse("Unknown"); System.out.println("值="+orElse); } }
我們可以使用 Optional.of 靜態(tài)工廠方法來創(chuàng)建一個(gè)包含非空值的 Optional 對(duì)象,如果傳入的值為 null,則會(huì)拋出 NullPointerException 異常。并可以使用 isPresent() 方法來判斷 Optional 對(duì)象是否包含非空值。如果包含非空值,則返回 true,否則返回 false。
也可以使用 Optional.ofNullable 靜態(tài)工廠方法,來創(chuàng)建一個(gè)包含指定值的 Optional 對(duì)象,如果傳入的值為 null,則會(huì)返回一個(gè)空的 Optional對(duì)象。然后使用 orElse() 方法來獲取 Optional 對(duì)象中包含的值,如果 Optional 對(duì)象為空,則返回指定的默認(rèn)值。
關(guān)于Optional的用法還有很多,以后會(huì)出一個(gè)Java新特性的專題系列,這里就不再細(xì)說了,敬請(qǐng)期待哦。
4.6 定位空指針異常
當(dāng)我們編寫的代碼真的產(chǎn)生了空指針異常,那該怎么辦呢?前面就跟大家說過,產(chǎn)生空指針異常的根本原因就是因?yàn)?rdquo;對(duì)象為空“,所以解決的辦法就是先找到這個(gè)為空的對(duì)象,然后給這個(gè)對(duì)象賦值,只要對(duì)象不為空,這個(gè)空指針異常就解決了。聽起來也不難,但真的開發(fā)時(shí),有時(shí)候經(jīng)驗(yàn)不豐富的程序員,可能一時(shí)半會(huì)還找不到是哪個(gè)對(duì)象為空了。因?yàn)槲覀兊捻?xiàng)目中,對(duì)象實(shí)在太多了!比如下面這樣的代碼:
a.b.c.method()
這里的a、b、c都是對(duì)象,假如就是這一行代碼產(chǎn)生了空指針,你說到底是哪個(gè)對(duì)象為空?有可能是a為空,也有可能是b,也有可能是c,通常我們得一個(gè)對(duì)象一個(gè)對(duì)象進(jìn)行判斷,比如通過打印日志進(jìn)行判斷:
System.out.println(a); System.out.println(a.b); System.out.println(a.b.c);
但是這樣寫代碼,就顯得啰嗦且低效!為了改善這種問題,在JDK 14中推出了新的API,JVM可以直接給出詳細(xì)的信息,告訴我們null對(duì)象到底是哪個(gè)。在JDK 14中,如果是上面的代碼產(chǎn)生了空指針異常,會(huì)出現(xiàn)這樣的提示信息:... because "....a.b" is null....
意思是b對(duì)象為null。但該功能默認(rèn)是關(guān)閉的,我們需要給JVM添加一個(gè)-XX:+ShowCodeDetailsInExceptionMessages
參數(shù)啟用它,如下:
java -XX:+ShowCodeDetailsInExceptionMessages Main.java
以上就是列舉出來的幾種避免及檢查空指針異常的常用方法,希望你可以掌握。
總之,我們?cè)诰帉慗ava程序時(shí),要格外注意避免空指針異常的發(fā)生,加強(qiáng)對(duì)變量和對(duì)象的判斷,養(yǎng)成良好的編碼習(xí)慣,就可以極大地降低NullPointerException的產(chǎn)生。如果發(fā)現(xiàn)值為null,就需要及早進(jìn)行處理,避免程序中斷或者崩潰。
五. 結(jié)語
這樣,就把空指針這種特別常見的異常單獨(dú)給大家分析了一下,希望大家以后遇到這種異常能夠知道怎么解決。今天的重點(diǎn)內(nèi)容如下:
- NullPointerException的根本原因是對(duì)象為空;
- 對(duì)空指針異常要早暴露,早修復(fù),不要使用catch進(jìn)行捕獲;
- 可以啟用Java 14的增強(qiáng)異常來定位空指針異常的產(chǎn)生位置。
以上就是詳解Java中NullPointerException的處理方法的詳細(xì)內(nèi)容,更多關(guān)于Java NullPointerException處理的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
java面向?qū)ο?API(接口)與集合(ArrayList)
這篇文章主要介紹了Java語言面向?qū)ο蟮腁PI與集合,還是十分不錯(cuò)的,這里給大家分享下,需要的朋友可以參考,希望能夠給你帶來幫助2021-08-08超詳細(xì)介紹idea中java程序打jar包的兩種方式
這篇文章主要介紹了超詳細(xì)介紹idea中java程序打jar包的兩種方式一種是可直接執(zhí)行的runnable jar文件,另一種是包含多個(gè)主類,運(yùn)行時(shí)需要指定主類全類名的jar包,感興趣的可以了解一下2020-07-07SpringMVC?RESTFul實(shí)戰(zhàn)案例訪問首頁
這篇文章主要為大家介紹了SpringMVC?RESTFul實(shí)戰(zhàn)案例訪問首頁,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05mybatis的映射xml中動(dòng)態(tài)設(shè)置orderby方式
這篇文章主要介紹了mybatis的映射xml中動(dòng)態(tài)設(shè)置orderby方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11Java?springBoot初步使用websocket的代碼示例
這篇文章主要介紹了Java?springBoot初步使用websocket的相關(guān)資料,WebSocket是一種實(shí)現(xiàn)實(shí)時(shí)雙向通信的協(xié)議,適用于需要實(shí)時(shí)通信的應(yīng)用程序,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2025-03-03Java給JFrame窗口設(shè)置熱鍵的方法實(shí)現(xiàn)
這篇文章主要介紹了Java給JFrame窗口設(shè)置熱鍵的方法實(shí)現(xiàn),文中通過示例代碼以及圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07