Java異常處理

1.什么是Java異常?

? ? ? ?今天我們來(lái)聊聊java異常,異常時(shí)導(dǎo)致程序中斷執(zhí)行的一種指令流。我們?cè)谔岣叽a穩(wěn)定性和健壯性的時(shí)候,常常會(huì)花更多的時(shí)間去考慮,代碼可能存在的異常。編碼中對(duì)可能的發(fā)生的異常先一步正確處理,就可以確保異常不會(huì)導(dǎo)致程序不可用。說(shuō)了這么多異常,那么異常是什么呢?

? ? ? ?Java異常是一種導(dǎo)致程序中斷的執(zhí)行指令流。它存在應(yīng)用服務(wù)器硬件錯(cuò)誤、程序編寫(xiě)的時(shí)候未考慮數(shù)組越界、也可能是網(wǎng)絡(luò)通信中網(wǎng)絡(luò)抖動(dòng)的客觀原因?qū)е碌漠惓5惹闆r。異??赡苁侵饔^代碼設(shè)計(jì)不周全也可能是客觀硬件報(bào)錯(cuò),那么認(rèn)識(shí)異常就是避免異常的第一步。我們先從異常家族的認(rèn)識(shí)開(kāi)始,下面異常的族譜:

? ? ? ?Throwable類(lèi)作為所有異常的發(fā)源,他是整個(gè)Java異常體系的超體,其下面分為Error和Exception兩大類(lèi)。

?? ? ? ?Error與其子類(lèi)實(shí)例代表嚴(yán)重系統(tǒng)錯(cuò)誤,應(yīng)用程序無(wú)法處理,如硬件層面的錯(cuò)誤、JVM錯(cuò)誤或內(nèi)存不足等問(wèn)題,這種錯(cuò)誤發(fā)生時(shí)Java應(yīng)用程序本身無(wú)力恢復(fù)。Error對(duì)象拋出時(shí),基本上不用處理,任其傳播至JVM為止,應(yīng)用程序能做的最多留下日志信息。

? ? ? ?Exception代表程序運(yùn)行時(shí)發(fā)送的各種不期望發(fā)生的事件??梢员籎ava異常處理機(jī)制使用,是異常處理的核心。Exception及其子類(lèi)可以被程序處理,也就是所在應(yīng)用程序中正確的處理了Exception及其子類(lèi)就能提高代碼的穩(wěn)定性和健壯性。

? ? ? ?Exception類(lèi)下面分為檢測(cè)異常和非檢測(cè)異常:

? ? ? ?檢測(cè)異常,是JVM強(qiáng)制要求程序員為可能出現(xiàn)的異常做預(yù)備處理工作。JVM規(guī)定檢測(cè)異常要么使用try-catch語(yǔ)句捕獲它并進(jìn)行處理,要么使用throws子句聲明并拋出它,否者javac在編譯程序會(huì)不通過(guò)。這類(lèi)異常一般是程序運(yùn)行環(huán)境導(dǎo)致的,為了預(yù)防未知環(huán)境對(duì)程序的影響,規(guī)定程序員需要處理這類(lèi)異常。

? ? ? ?非檢測(cè)異常,javac在編譯時(shí),不會(huì)提示和發(fā)現(xiàn)異常的存在,JVM不強(qiáng)制要求程序員處理這樣的異常。當(dāng)然,作為程序員我們應(yīng)該預(yù)防這樣的異常導(dǎo)致程序崩潰,所以建議使用try-catch-finally處理它。這類(lèi)異常原因多半是代碼寫(xiě)的邏輯有問(wèn)題或考慮不周全。

2.當(dāng)一個(gè)Exception在程序中發(fā)生的時(shí)候,JVM是怎么做的呢?

? ? ? ?對(duì)java整體異常家族有了大致的認(rèn)識(shí)之后,那么當(dāng)一個(gè)Exception在程序中發(fā)生的時(shí)候,JVM是怎么做的呢?

? ? ? ?認(rèn)識(shí)這個(gè)問(wèn)題,我們首看看JVM是如何執(zhí)行java代碼的,按照?qǐng)?zhí)行步驟可以分為,JVM將class文件轉(zhuǎn)換為JVM的java類(lèi)。JVM為java類(lèi)建立方法表,方法表中的索引可以引導(dǎo)JVM找到需要執(zhí)行的方法體和JVM方法執(zhí)行棧。當(dāng)然,invokemethod調(diào)用執(zhí)行一個(gè)方法的時(shí)候,Java虛擬機(jī)把描述該方法的棧結(jié)構(gòu)置入方法執(zhí)行棧棧頂,位于棧頂?shù)姆椒檎趫?zhí)行的方法。JVM會(huì)為每一個(gè)方法建立執(zhí)行的堆和棧用于存放執(zhí)行中的變量,如果此時(shí)程序出現(xiàn)一個(gè)Exception,拋出的異常先轉(zhuǎn)移給合適的異常處理語(yǔ)句。代碼的執(zhí)行會(huì)被相應(yīng)的Exception執(zhí)行流接管,將方法表信息、發(fā)生異常的位置信息和方法的堆棧信息壓入Exception的堆棧,當(dāng)程序中斷的時(shí)候IDE就會(huì)將Exception的堆棧信息打印出來(lái)。

? ? ? ?如果我們通過(guò)try…..catch….finally語(yǔ)句來(lái)處理異常,處理流程又是怎樣的呢?在try代碼塊中拋出的異常,代碼執(zhí)行流會(huì)跳轉(zhuǎn)到catch代碼塊執(zhí)行,catch代碼塊可以對(duì)發(fā)生的異常進(jìn)行補(bǔ)救。讓代碼回歸到正常的執(zhí)行流程。finally語(yǔ)句,無(wú)論在try模塊中是否發(fā)生異常,都會(huì)執(zhí)行finally語(yǔ)句,使用finally語(yǔ)句主要是為了釋放被占用的資源,比如打開(kāi)的文件或鏈接的通信資源等。

? ? ? ?總體來(lái)說(shuō),Java語(yǔ)言的異常處理流程,從程序中獲取異常信息。根據(jù)Java的源文件和用戶(hù)調(diào)用的包列表,JVM可以獲取該程序包括Java API所引發(fā)的異常在內(nèi)的異常處理的信息,這些信息包括:異常引發(fā)位置、異常拋出順序、引發(fā)異常的方法名和類(lèi)名等。這些異常信息在程序異常的排查和修改的時(shí)候非常重要,后面會(huì)講到如何正確處理這些異常。

3.當(dāng)我們編寫(xiě)程序的時(shí)候如何對(duì)待可能出現(xiàn)的異常呢?

? ? ? ?通常在發(fā)生異常的時(shí)候我們有兩種處理模型:終止與恢復(fù)。

? ? ? ?終止模型:前提是假設(shè)錯(cuò)誤非常關(guān)鍵,以至于程序無(wú)法返回到程序正常運(yùn)行軌跡,一旦異常拋出就意味著程序?qū)⑼V固峁┓?wù)。如:數(shù)據(jù)庫(kù)連接異常發(fā)生

? ? ? ?恢復(fù)模型:也就是異常程序發(fā)生錯(cuò)誤,錯(cuò)誤可以被修復(fù)然后重新回到正常程序執(zhí)行的軌跡上。例如,我們可以將數(shù)據(jù)庫(kù)連接try。。。catch置于循環(huán)中,一次連接不成功可以循環(huán)下一次進(jìn)行連接。

? ? ? ?配合終止和恢復(fù)模型,我們會(huì)配合使用throw和throws語(yǔ)法。throws關(guān)鍵字主要在方法簽名中使用,用于聲明該方法可能拋出的異常。throws 可以理解成是一種通知行為沒(méi)有實(shí)際的拋出異常的動(dòng)作,而僅僅是告訴調(diào)用他的上層函數(shù),這里可能會(huì)拋出這個(gè)異常;

? ? ? ?throw用于在函數(shù)體內(nèi)語(yǔ)句中,表示拋出一個(gè)實(shí)際的異常的實(shí)際動(dòng)作,如果在函數(shù)內(nèi)沒(méi)有捕獲并處理,那么將會(huì)一直向上拋出這個(gè)異常直到被main()/Thread.run()拋出。

? ? ? ?我們了解了Java的異常內(nèi)容之后,在程序中遵循怎樣的行業(yè)規(guī)則和大牛的經(jīng)驗(yàn)合理使用異常,提高代碼的穩(wěn)定性呢?

? ? ? ?下面整理了包括Effective Java異常使用指導(dǎo)原則和網(wǎng)上博客內(nèi)容:

1.? ?不要講異常處理用于正常的控制流(設(shè)計(jì)良好的API不應(yīng)該強(qiáng)迫它的調(diào)用者為了正常的控制流而使用異常)。

2.? ? 對(duì)可以恢復(fù)的情況使用了受檢異常,對(duì)編程錯(cuò)誤使用運(yùn)行時(shí)異常。

3.? ? 避免不必要的使用受檢異常(可以通過(guò)一些狀態(tài)檢測(cè)手段來(lái)避免異常的發(fā)生)。

4.? ? 優(yōu)先使用標(biāo)準(zhǔn)異常。

5.? ? 每個(gè)方法拋出的異常都要有文檔。

6.? ? 保持異常的原子性。

7.? ? 不要再catch中忽略掉捕獲到的異常。

8.? ? 處理運(yùn)行時(shí)異常,采用邏輯合理規(guī)避同時(shí)輔助try…catch處理。

9.? ? 在多重catch快后面,可以加一個(gè)catch(Exception)來(lái)處理可能會(huì)被遺漏的異常。

10.? 對(duì)于不確定的代碼,也可以加上try…catch,處理潛在的異常。

11.? 盡量去處理異常,切忌只是簡(jiǎn)單的調(diào)用printStackTrace()打印輸出。

12.? 具體如何處理異常,要根據(jù)不同的業(yè)務(wù)需求和異常類(lèi)型去決定。

13.? 盡量添加finally語(yǔ)句塊去釋放占用的資源。

? ? ? ?不要被這么多規(guī)則嚇到了,不需要逐條強(qiáng)記他們。我對(duì)異常的理解,首先態(tài)度上要謙虛明白代碼中很難避免因?yàn)榭紤]不周出現(xiàn)的異常,所以編碼時(shí)應(yīng)該采用防衛(wèi)式編碼。其次在編碼處理過(guò)程中使用try…catch…finally語(yǔ)句預(yù)防可能的異常,采用合適的異常處理模式對(duì)待程序可能的異常。

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

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

  • 2.JAVA異常 異常指不期而至的各種狀況,如:文件找不到、網(wǎng)絡(luò)連接失敗、非法參數(shù)等。異常是一個(gè)事件,它發(fā)生在程...
    青城樓主閱讀 596評(píng)論 0 0
  • 六種異常處理的陋習(xí) 你覺(jué)得自己是一個(gè)Java專(zhuān)家嗎?是否肯定自己已經(jīng)全面掌握了Java的異常處理機(jī)制?在下面這段代...
    Executing閱讀 1,410評(píng)論 0 6
  • 初識(shí)異常(Exception) 比如我們?cè)谌?shù)組里面的某個(gè)值得時(shí)候,經(jīng)常會(huì)出現(xiàn)定義的取值范圍超過(guò)了數(shù)組的大小,那么...
    iDaniel閱讀 1,966評(píng)論 1 2
  • 概念介紹 異常是發(fā)生在程序執(zhí)行過(guò)程中阻礙程序正常執(zhí)行的錯(cuò)誤事件,當(dāng)一個(gè)程序出現(xiàn)錯(cuò)誤時(shí),可能的情況有如下3種: 語(yǔ)法...
    niaoge2016閱讀 5,610評(píng)論 2 20
  • 3月7日凌晨0點(diǎn)55分,躺在床上,我在想我是誰(shuí)。 在躺在床上之前一刻,我都堅(jiān)信,今天交不了作業(yè)了。因?yàn)橥砩?點(diǎn)半回...
    花椒抹茶酥閱讀 164評(píng)論 0 0

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