程序员基本功08异常捕捉的陷阱
1、使用finally正確地關(guān)閉資源
在實際開發(fā)中,經(jīng)常需要 在程序中打開一些物理資源,如數(shù)據(jù)庫連接、網(wǎng)絡(luò)連接、磁盤文件等,打開這些物理資源后必須顯示關(guān)閉,否則將引起資源泄露。JVM的垃圾回收機(jī)制屬于Java內(nèi)存管理的一部分,它只負(fù)責(zé)回收堆內(nèi)存中分配出來的內(nèi)存,至于程序中打開的物理資源,垃圾回收機(jī)制無能為力。
finally{if(oos!=null){try{oos.close(); }catch(Exception ex){ex.printStackTrace(); } } }使用finally塊來關(guān)閉物理資源,保證關(guān)閉操作總會被執(zhí)行;
關(guān)閉每個資源之前首先保證引用該資源的引用變量不為null;
為每個物理資源使用單獨(dú)try...catch塊關(guān)閉資源,保證關(guān)閉資源時引發(fā)的異常不會影響其他資源的關(guān)閉
2、finally遇到return的處理
只要JVM不退出,finally代表總是會被執(zhí)行的代碼塊,因此finally塊總是用來關(guān)閉物理資源,從而保證程序物理資源總能被正常關(guān)閉。
當(dāng)Java程序執(zhí)行try塊、catch塊時遇到了return語句,return語句會導(dǎo)致該方法立即結(jié)束。系統(tǒng)執(zhí)行完return語句后,并不會立即結(jié)束該方法,而是去尋找該異常處理流程中是否包含finally塊,若果沒有,方法終止,返回相應(yīng)的返回值。如果有finally塊,系統(tǒng)立即執(zhí)行finally塊---只有當(dāng)finally塊執(zhí)行完成后,系統(tǒng)才會再次跳回來根據(jù)return語句結(jié)束方法。如果finally使用return語句來結(jié)束方法,系統(tǒng)不會調(diào)回去執(zhí)行try塊、catch塊里任何代碼。
同理,當(dāng)程序執(zhí)行try塊、catch塊時遇到throw語句時,throw語句會導(dǎo)致該方法立即結(jié)束,系統(tǒng)執(zhí)行throw語句并不會立即拋異常,而是尋找該異常處理流程中是否包含finally塊,如果沒有,程序拋異常;如果有,系統(tǒng)執(zhí)行finally塊,只有finally塊執(zhí)行完成后,系統(tǒng)才會再次跳出來拋異常。如果finally使用return結(jié)束方法,系統(tǒng)不會跳回去執(zhí)行try塊、catch塊去拋異常。
3、finally遇到System.exit()的處理
當(dāng)Syatem.exit(0)被調(diào)用時,虛擬機(jī)退出前執(zhí)行兩項清理工作:
- 執(zhí)行系統(tǒng)中注冊的所有關(guān)閉鉤子;(安全)
- 如果程序調(diào)用了System.runFinaluzerOnExit(true):那么JVM會對所有還為結(jié)束的對象調(diào)用Finalize。(此種行為危險)
4、catch塊只能先捕捉子類異常
對于Java異常捕捉,每個try塊至少需要一個或多個catch塊或一個finally塊,絕不能只有try。當(dāng)Java運(yùn)行環(huán)境接收到異常對象時,系統(tǒng)會根據(jù)catch(XxxException e)語句決定使用哪個異常分支來處理程序引發(fā)的異常。當(dāng)程序進(jìn)入負(fù)責(zé)異常處理的catch塊時,系統(tǒng)生成的異常對象ex將會被傳給catch(XxxException e)語句的異常形參,從而允許catch塊通過該對象來訪問異常的詳細(xì)信息。通過提供catch塊,無需在異常處理中使用if、switch判斷異常類型,但依然可以針對不同異常類型提供相應(yīng)的處理邏輯,從而提供細(xì)致、條里的異常處理邏輯。通常情況下,try塊被執(zhí)行一次,則try塊后只有一個catch會被執(zhí)行,絕不能有多個catch塊被執(zhí)行。除非在循環(huán)中使用了continue開始下一次循環(huán),下一次循環(huán)又重新運(yùn)行了try塊,導(dǎo)致catch塊被執(zhí)行。
異常處理機(jī)制中排在前面的catch(XxxExpection)塊總是會優(yōu)先獲得執(zhí)行的機(jī)會,一次對catch塊的排列順序是有要求的:先捕捉小的異常,再捕捉大的異常。Exception是所有異常類的根父類,因此應(yīng)把Exception塊排在所有catch塊的最后面。
5、只有catch可能拋出的異常
不要在程序中使用異常機(jī)制,更不要使用異常處理機(jī)制來代替流程控制,對于程序中各種能夠預(yù)知的情況,應(yīng)該盡量處理,不要盲目使用異常捕捉來代替流程控制。
6、catch塊內(nèi)應(yīng)做實際的修復(fù)
如果知道如何修復(fù)指定異常,應(yīng)該在catch塊內(nèi)盡量修復(fù)異常,當(dāng)該異常被修復(fù)后,可以再次調(diào)用該方法;如不知道如何修復(fù),也沒有任何修復(fù),千萬不要再次調(diào)用可能導(dǎo)致該異常的方法。否則會形成無限遞歸,最終導(dǎo)致java.lang.StackOverflowError錯誤非正常結(jié)束。
7、只能聲明拋出所實現(xiàn)方法允許聲明拋出異常的交集
Java語言規(guī)定,子類重寫父類方法時,不能聲明拋出比父類方法類型更多、范圍更大的異常。也就是說,子類只能聲明父類方法中所聲明拋出的異常子類。當(dāng)一個子類同時實現(xiàn)多個接口時,其只能拋出倆個接口聲明異常的交集或者不寫。
總結(jié)
以上是生活随笔為你收集整理的程序员基本功08异常捕捉的陷阱的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 程序员基本功10栈和队列
- 下一篇: 程序员基本功 07 面向对象的陷阱