當當當當當當趴樱,各位看官,好久不見酪捡,甚是想念叁征。
今天我們來聊聊Java里的一個小妖精,那就是異常逛薇。
什么是異常捺疼?什么是異常處理?
異常嘛永罚,顧名思義就是不正常啤呼,(逃),是Java程序運行時呢袱,發(fā)生的預料之外的事情官扣,它阻止了程序按照程序員的預期正常執(zhí)行。
異常處理羞福,應該說異常處理機制惕蹄,就是專門用來制服這個小妖精的法寶。Java中的異常處理機制能讓程序在異常發(fā)生時治专,按照代碼的預先設(shè)定的異常處理邏輯卖陵,針對性地處理異常,讓程序盡最大可能恢復正常并繼續(xù)執(zhí)行张峰,且保持代碼的清晰泪蔫。
簡而言之,Java異常處理就是能讓我們主動迎擊可能到來的異常喘批,并將它們以圓潤的方式處理掉撩荣。
還是先來看個小栗子,看看java里的異常長什么樣谤祖。
public class Test {
public static void main(String args[]){
int i = 0 / 0;
System.out.println("i = " + i);
}
}
別慌別慌婿滓,不要看到紅色提示就內(nèi)心崩潰只想關(guān)掉IDE,來粥喜,抓緊我的手凸主,帶你看清“異常”這個磨人的小妖精的真面目(滑稽)额湘。
代碼里將0作為了分母卿吐,因此程序會發(fā)生算術(shù)異常旁舰,拋出一個異常后,如果沒有任何處理嗡官,默認會終止程序箭窜,所以后面的打印內(nèi)容并沒有輸出。在異常內(nèi)容里衍腥,有說明異常類型為:java.lang.ArithmeticException磺樱,也就是算術(shù)異常,后面跟著的是異常原因: / by zero婆咸,也就是說異常出現(xiàn)的原因是將0作為了分母竹捉,而且后面還有堆棧信息,指出了異常拋出的位置是在com.frank.chapter16.main.Test.main這個包下尚骄,Test類的第11行(這個行數(shù)如果跟你想的不一樣块差,不要在意,因為我的代碼開始之前還有一些不可描述的說明信息)倔丈,因為只有一次方法調(diào)用憨闰,所以沒有很長的堆棧信息,看起來也很簡潔明了需五。
所以你看鹉动,其實異常也沒那么可怕吧,不僅給了異常原因宏邮,還告訴了你這個bug是出在第幾行训裆,所以好好利用它,可以幫助你寫出更難以發(fā)現(xiàn)的bug蜀铲,呸,說錯了属百,可以幫助你更容易找到bug(手動滑稽)记劝。
如果不希望拋出異常后程序就結(jié)束,而是希望它繼續(xù)運行呢族扰?那么就捕獲它厌丑。
如何使用異常處理
我們來把上面那個栗子改改:
public class Test {
public static void main(String args[]){
try{
int i = 0 / 0;
}catch (Exception e){
System.out.println("好像發(fā)生異常了,但是我不管渔呵,我還要繼續(xù)運行");
}
System.out.println("運行完畢!");
}
}
輸出如下:
好像發(fā)生異常了怒竿,但是我不管,我還要繼續(xù)運行
運行完畢!
好的扩氢,很強勢耕驰,現(xiàn)在即使拋出了異常,程序也繼續(xù)運行了录豺。異常就像是一頭野獸朦肘,但你一旦捕獲它饭弓,馴服它,就可以為你所用媒抠,為所欲為了弟断。
try...catch...是常用的異常處理搭配,如果在try語句塊中發(fā)生了異常趴生,如果剛好這個異常被捕獲到了阀趴,那么會直接跳到catch語句塊中,執(zhí)行catch語句中的代碼苍匆,像上面的栗子里刘急,因為對Exception類進行了捕獲處理,所以當它的子類異常java.lang.ArithmeticException被拋出來的時候锉桑,也能捕獲它排霉。關(guān)于Exception類的結(jié)構(gòu)層次關(guān)系,后面再做詳細介紹民轴。
還有另外一種搭配方式攻柠,那就是try...catch...finally,finally語句塊比catch要強勢的多后裸,前面說了catch語句塊必須要捕獲到了特定的Exception才會執(zhí)行里面的代碼瑰钮,如果catch的是ArithmeticException但是拋出的卻是空指針異常,那就不會被捕獲了微驶,異常也就逃之夭夭了浪谴。這個時候,finally的優(yōu)勢就展示出來了因苹,不管拋出什么樣的異常苟耻,也不管是否拋出了異常,finally中的代碼都會被執(zhí)行扶檐。所以一般的用法是在finally語句塊里釋放掉那些需要被釋放的資源凶杖,如socket連接,關(guān)閉io流款筑,關(guān)閉數(shù)據(jù)庫連接等等智蝠。也就是說一般在finally中收拾try中拋出的爛攤子,心疼一秒finally奈梳,果然能者多勞啊杈湾。
當然,try...finally這樣的搭配也是ok的攘须,需要注意的是漆撞,當try語句中發(fā)生了異常之后,在發(fā)生異常處之后的代碼將不會再執(zhí)行,而是跳到相應的catchu或者finally中去叫挟。
public class Test {
public static void main(String args[]){
try{
int i = 0 / 0;
}catch (NullPointerException e) {
System.out.println("這里捕獲空指針異常");
}catch (ArithmeticException e){
System.out.println("這里捕獲算術(shù)異常");
}finally {
System.out.println("這里是finally");
}
System.out.println("運行完畢!");
}
}
輸出如下:
這里捕獲算術(shù)異常
這里是finally
運行完畢!
在上面的代碼中艰匙,catch語句塊是可以同時使用多個的,第一個catch語句塊捕獲的是空指針異常抹恳,但由于拋出的是算術(shù)異常员凝,所以沒有捕獲住,但被第二個catch捕獲到了奋献,所以第二個catch語句塊中的代碼執(zhí)行了健霹。異常匹配是按照從上到下的順序進行匹配的,最后才執(zhí)行finally中的代碼塊瓶蚂。關(guān)于try...catch...finally糖埋,還有一個很有趣的return問題,如果三個語句塊里都有return窃这,最終返回結(jié)果會是怎樣呢瞳别?
絕大多數(shù)情況下,finally中的代碼都是會被執(zhí)行的杭攻,只有一種情況下祟敛,finally中的代碼不會被執(zhí)行,那就是在try語句塊中結(jié)束掉了虛擬機(如:使用 System.exit(0); )兆解。
關(guān)于異常馆铁,還有一個關(guān)鍵字需要介紹,那就是throw锅睛,使用throw可以主動拋出一個異常埠巨。看到這你也許會一臉懵逼现拒,主動拋出辣垒??印蔬?嫌異常不夠多乍构,湊熱鬧不嫌事大?扛点?別急別急,中間一定有什么誤會岂丘,把刀放下陵究,有話好好說。
throw關(guān)鍵字確實是用來拋出異常的奥帘,你可以這樣使用:
public class Test {
public static void main(String args[]){
try{
throw new NullPointerException("聽說你很閑铜邮,給你拋個異常。");
}catch (NullPointerException e) {
System.out.println("這里捕獲空指針異常,提示內(nèi)容:" + e.getMessage());
e.printStackTrace();
}
}
}
輸出如下:
這里捕獲空指針異常松蒜,提示內(nèi)容:聽說你很閑扔茅,給你拋個異常。
java.lang.NullPointerException: 聽說你很閑秸苗,給你拋個異常召娜。
at com.frank.chapter16.main.Test.main(Test.java:11)
用throw關(guān)鍵字可以拋出任意類型的異常,當然惊楼,你想的話玖瘸,還有拋Error,至于什么是Error檀咙,已經(jīng)跟Exception的關(guān)系雅倒,將在下一篇里進行講解。暫時不用深究弧可。
在throw異常的時候蔑匣,可以加上拋出異常的原因,這樣可以更方便定位問題所在棕诵,當然裁良,一般來說不會像栗子中這樣使用的,這里只是為了簡單起見年鸳。
到此為止趴久,異常的上半篇已經(jīng)講解完畢,在這一篇里搔确,說明了什么是異常彼棍,什么是異常處理,以及如何使用異常處理機制膳算。相信大家對這個小妖精有了初步的認識座硕,下一篇中,將會講解Exception家族都有哪些成員涕蜂,如何使用自定義異常华匾,已經(jīng)異常處理的實際使用中的正確姿勢。歡迎大家繼續(xù)關(guān)注机隙,之后計劃每周兩篇以上的更新蜘拉,如果有講解遺漏或者不好的地方,歡迎大家及時指出有鹿,共同進步旭旭!
我做開發(fā)十多年的時間,如果大家對于學習java的學習方法葱跋,學習路線以及你不知道自己應該是自學還是培訓的疑問持寄,都可以隨時來問我源梭,大家可以加我的java交流學習qun:四九四,八零一稍味,九三一废麻,qun內(nèi)有學習教程以及開發(fā)工具。