淺談java異常處理之空指針異常
聽老師說,在以后的學(xué)習(xí)中大部分的異常都是空指針異常。所以抽點(diǎn)打游戲的時(shí)間來查詢一下什么是空指針異常
一:空指針異常產(chǎn)生的主要原因如下:
(1)當(dāng)一個(gè)對(duì)象不存在時(shí)又調(diào)用其方法會(huì)產(chǎn)生異常obj.method() // obj對(duì)象不存在
(2)當(dāng)訪問或修改一個(gè)對(duì)象不存在的字段時(shí)會(huì)產(chǎn)生異常obj.method() // method方法不存在
(3)字符串變量未初始化;
(4)接口類型的對(duì)象沒有用具體的類初始化,比如:
List lt;會(huì)報(bào)錯(cuò)
List lt = new ArrayList();則不會(huì)報(bào)錯(cuò)了
當(dāng)一個(gè)對(duì)象的值為空時(shí),你沒有判斷為空的情況。你可以試著把下面的代碼前加一行代碼:
if(rb!=null && rb!="")
改成:
if(rb==null); if(rb!==null&&rb!="") 或者if((“”).equals(rb))
空指針的解決辦法:
重點(diǎn)關(guān)注報(bào)錯(cuò)發(fā)生的所在行,通過空指針異常產(chǎn)生的兩條主要原因診斷具體的錯(cuò)誤。同時(shí)為了避免空指針的發(fā)生,最好在做判斷處理時(shí)將“null”或者空值放于設(shè)定的值之前。
常見空指針異常的簡要分析:
(1)空指針錯(cuò)誤 Java.lang.NullPointerException
Java中的8種基本數(shù)據(jù)類型,變量的值可以有其默認(rèn)值,加入沒有對(duì)其正常賦值,java虛擬機(jī)是不能正確編譯通過的,因此使用基本的Java數(shù)據(jù)類型一般不會(huì)是不會(huì)引起空指針異常的。實(shí)際開發(fā)中,大多數(shù)的空指針異常主要與對(duì)象的操作相關(guān)。
二、Java 異常處理機(jī)制
對(duì)于可能出現(xiàn)異常的代碼,有兩種處理辦法:
第一、在方法中用try...catch 語句捕獲并處理異常,catach 語句可以有多個(gè),用來匹配多個(gè)異常。例如:
public void p(int x){ try{ ... }catch(Exception e){ ... }finally{ ... }}
第二、對(duì)于處理不了的異常或者要轉(zhuǎn)型的異常,在方法的聲明處通過
throws 語句拋出異常。例如:
public void test1() throws MyException{ ... if(....){ throw new MyException(); }}
如果每個(gè)方法都是簡單的拋出異常,那么在方法調(diào)用方法的多層嵌套調(diào)用中,Java 虛擬機(jī)會(huì)從出現(xiàn)異常的方法代碼塊中往回找,直到找到處理該異常的代碼塊為止。然后將異常交給相應(yīng)的catch 語句處理。如果Java 虛擬機(jī)追溯到方法調(diào)用棧最底部main()方法時(shí),如果仍然沒有找到處理異常的代碼塊,將按照下面的步驟處理:
第一、調(diào)用異常的對(duì)象的printStackTrace()方法,打印方法調(diào)用棧的異常信息。
第二、如果出現(xiàn)異常的線程為主線程,則整個(gè)程序運(yùn)行終止;如果非主線程,則終止該線程,其他線程繼續(xù)運(yùn)行。
通過分析思考可以看出,越早處理異常消耗的資源和時(shí)間越小,產(chǎn)生影響的范圍也越小。因此,不要把自己能處理的異常也拋給調(diào)用者。
還有一點(diǎn),不可忽視:finally 語句在任何情況下都必須執(zhí)行的代碼,這樣可以保證一些在任何情況下都必須執(zhí)行代碼的可靠性。比如,在數(shù)據(jù)庫查詢異常的時(shí)候,應(yīng)該釋放JDBC 連接等等。finally 語句先于return 語句執(zhí)行,而不論其先后位置,也不管是否try 塊出現(xiàn)異常。finally 語句唯一不被執(zhí)行的情況是方法執(zhí)行了System.exit()方法。System.exit()的作用是終止當(dāng)前正在運(yùn)行的Java 虛擬機(jī)。finally 語句塊中不能通過給變量賦新值來改變r(jià)eturn的返回值,也建議不要在finally 塊中使用return 語句,沒有意義還容易導(dǎo)致錯(cuò)誤。
最后還應(yīng)該注意一下異常處理的語法規(guī)則:
第一、try 語句不能單獨(dú)存在,可以和catch、finally 組成
try...catch...finally、try...catch、try...finally 三種結(jié)構(gòu),catch 語句可以有一個(gè)或多個(gè),finally 語句最多一個(gè),try、catch、finally 這三個(gè)關(guān)鍵字均不能單獨(dú)使用。
第二、try、catch、finally 三個(gè)代碼塊中變量的作用域分別獨(dú)立而不能相互訪問。如果要在三個(gè)塊中都可以訪問,則需要將變量定義到這些塊的外面。
第三、多個(gè)catch 塊時(shí)候,Java 虛擬機(jī)會(huì)匹配其中一個(gè)異常類或其子類,就執(zhí)行這個(gè)catch 塊,而不會(huì)再執(zhí)行別的catch 塊。
第四、throw 語句后不允許有緊跟其他語句,因?yàn)檫@些沒有機(jī)會(huì)執(zhí)行。
第五、如果一個(gè)方法調(diào)用了另外一個(gè)聲明拋出異常的方法,那么這個(gè)方法要么處理異常,要么聲明拋出。
2.2throw 和throws 關(guān)鍵字的區(qū)別:
throw 用來拋出一個(gè)異常,在方法體內(nèi)。語法格式為:throw 異常對(duì)象。
throws 用來聲明方法可能會(huì)拋出什么異常,在方法名后,語法格式為:
throws 異常類型1,異常類型2...異常類型n。
三:下面列出可能發(fā)生空指針異常的幾種情況及相應(yīng)解決方案:
代碼段1:
out.println(request.getParameter("username"));
分析:代碼段1的功能十分簡單,就是輸出用戶輸入"username"的值。
說明:看上去,上面的語句找不出什么語法錯(cuò)誤,而且在大多數(shù)情況下也遇不到什么問題。但是,如果某個(gè)用戶在輸入數(shù)據(jù)時(shí)并沒有提供表單 域"username" 的值,或通過某種途徑繞過表單直接輸入時(shí),此request.getParameter("username")的值為空(注意不是空字符串,是空對(duì)象 null。),out對(duì)象的println方法是無法直接對(duì)空對(duì)象操作的,因此代碼段1所在的JSP頁面將會(huì)拋出 "Java.lang.NullPointerException"異常。而且即使對(duì)象可能為空時(shí),也調(diào)用Java.lang.Object或 Object對(duì)象本身的一些方法如toString(), equal(Object obj)等操作。
代碼段2:
String userName = request.getParameter("username"); If (userName.equals("root")) {....}
分析:代碼段2的功能是檢測用戶提供的用戶名,如果是用戶名稱為"root"的用戶時(shí),就執(zhí)行一些特別的操 作。
說明:在代碼段2中,如果有用戶沒有提供表單域"username"的值時(shí),字符串對(duì)象userName為null值,不能夠?qū)⒁粋€(gè)null的對(duì)象與另一 個(gè)對(duì)象直接比較,同樣,代碼段2所在的JSP頁面就會(huì)拋空指針錯(cuò)誤。
一個(gè)小技巧:如果要把某個(gè)方法的返回值與常量做比較,把常量放在前面,可以避免調(diào)用null對(duì)象的equals方法。譬如:
If ("root".equals(userName)) {....}
即使userName對(duì)象返回了null對(duì)象,這里也不會(huì)有空指針異常,可以照常運(yùn)轉(zhuǎn)。
代碼段3:
String userName = session.getAttribute("session.username").toString();
分析:代碼段3的功能是將session中session.username的值取出,并將該值賦給字符串對(duì)象userName。
說明:在一般情況下,如果在用戶已經(jīng)進(jìn)行某個(gè)會(huì)話,則不會(huì)出現(xiàn)什么問題;但是,如果此時(shí)應(yīng)用服務(wù)器重新啟動(dòng),而用戶還沒有重新登錄,(也可能是用戶關(guān)閉瀏 覽器,但是仍打開原來的頁面。)那么,此時(shí)該session的值就會(huì)失效,同時(shí)導(dǎo)致session中的session.username的值為空。對(duì)一個(gè) 為 null的對(duì)象的直接執(zhí)行toString()操作,就會(huì)導(dǎo)致系統(tǒng)拋出空指針異常。
代碼段4:
public static void main(String args[]){ Person p=null; p.setName("張三"); System.out.println(p.getName()); }
分析:聲明一個(gè)Person對(duì)象,并打印出該對(duì)象的中的Name名字。
說明:這個(gè)時(shí)候你的p就出現(xiàn)空指針異常,因?yàn)槟阒皇锹暶髁诉@個(gè)Person類型的對(duì)象并沒有創(chuàng)建對(duì)象,所以它的堆里面沒有地址引用,切忌你要用對(duì) 象掉用方法的時(shí)候一定要?jiǎng)?chuàng)建對(duì)象。
A:不管對(duì)象是否為空就直接開始使用。
(JSP)代碼段1:
out.println(request.getParameter("username"));
分析:代碼段1的功能十分簡單,就是輸出用戶輸入"username"的值。
說明:看上去,上面的語句找不出什么語法錯(cuò)誤,而且在大多數(shù)情況下也遇不到什么問題。但是,如果某個(gè)用戶在 輸入數(shù)據(jù)時(shí)并沒有提供表單域"username" 的值,或通過某種途徑繞過表單直接輸入時(shí),此request.getParameter("username")的值為空(注意不是空字符串,是空對(duì)象 null。),out對(duì)象的println方法是無法直接對(duì)空對(duì)象操作的,因此代碼段1所在的JSP頁面將會(huì)拋出 "Java.lang.NullPointerException"異常。而且即使對(duì)象可能為空時(shí),也調(diào)用Java.lang.Object或Object對(duì)象本身的一些方法如toString(), equal(Object obj)等操作。
(JSP)代碼段2:
String userName = request.getParameter("username"); If (userName.equals("root")) {....}
分析:代碼段2的功能是檢測用戶提供的用戶名,如果是用戶名稱為"root"的用戶時(shí),就執(zhí)行一些特別的操作。
說明:在代碼段2中,如果有用戶沒有提供表單域"username"的值時(shí),字符串對(duì)象userName為null值,不能夠?qū)⒁粋€(gè)null的對(duì)象與另一個(gè)對(duì)象直接比較,同樣,代碼段2所在的JSP頁面就會(huì)拋(Java.lang.NullPointerException)空指針錯(cuò)誤。
(JSP)代碼段3:
String userName = session.getAttribute ("session.username").toString();
分析:代碼段3的功能是將session中session.username的值取出,并將該值賦給字符串對(duì)象userName。
說明:在一般情況下,如果在用戶已經(jīng)進(jìn)行某個(gè)會(huì)話,則不會(huì)出現(xiàn)什么問題;但是,如果此時(shí)應(yīng)用服務(wù)器重新啟動(dòng) ,而用戶還沒有重新登錄,(也可能是用戶關(guān)閉瀏覽器,但是仍打開原來的頁面。)那么,此時(shí)該session的值就會(huì)失效,同時(shí)導(dǎo)致session中的session.username的值為空。對(duì)一個(gè)為 null的對(duì)象的直接執(zhí)行toString()操作,就會(huì)導(dǎo)致系統(tǒng)拋出(Java.lang.NullPointerException)空指針異常。
以上就是小編為大家?guī)淼臏\談java異常處理之空指針異常全部內(nèi)容了,希望大家多多支持腳本之家~
相關(guān)文章
springboot添加多數(shù)據(jù)源的方法實(shí)例教程
這篇文章主要給大家介紹了關(guān)于springboot添加多數(shù)據(jù)源方法的相關(guān)資料,在實(shí)際開發(fā)中經(jīng)??赡苡龅皆谝粋€(gè)應(yīng)用中可能要訪問多個(gè)數(shù)據(jù)庫多的情況,需要的朋友可以參考下2023-09-09基于Spring BeanUtils的copyProperties方法使用及注意事項(xiàng)
這篇文章主要介紹了基于Spring BeanUtils的copyProperties方法使用及注意事項(xiàng),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06idea設(shè)置在包里面在創(chuàng)建一個(gè)包方式
這篇文章主要介紹了idea設(shè)置在包里面在創(chuàng)建一個(gè)包方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-05-05SpringBoot security安全認(rèn)證登錄的實(shí)現(xiàn)方法
這篇文章主要介紹了SpringBoot security安全認(rèn)證登錄的實(shí)現(xiàn)方法,也就是使用默認(rèn)用戶和密碼登錄的操作方法,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2023-02-02Java線程實(shí)現(xiàn)時(shí)間動(dòng)態(tài)顯示
這篇文章主要為大家詳細(xì)介紹了Java線程實(shí)現(xiàn)時(shí)間動(dòng)態(tài)顯示,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-04-04java 進(jìn)制轉(zhuǎn)換實(shí)例詳解
這篇文章主要介紹了java 進(jìn)制轉(zhuǎn)換實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-04-04Java中消息隊(duì)列任務(wù)的平滑關(guān)閉詳解
對(duì)于消息隊(duì)列的監(jiān)聽,我們一般使用Java寫一個(gè)獨(dú)立的程序,在Linux服務(wù)器上運(yùn)行。程序啟動(dòng)后,通過消息隊(duì)列客戶端接收消息,放入一個(gè)線程池進(jìn)行異步處理,并發(fā)的快速處理。這篇文章主要給大家介紹了關(guān)于Java中消息隊(duì)列任務(wù)的平滑關(guān)閉的相關(guān)資料,需要的朋友可以參考下。2017-11-11Jenkins一鍵打包部署SpringBoot應(yīng)用的方法步驟
本文主要介紹了使用Jenkins一鍵打包部署SpringBoot應(yīng)用的方法步驟,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-12-12