try塊與if語句不一樣, try塊后的花括號不可以省略,即使只有一行代碼,也不能省略花括號。與之類似的是 catch塊后的花括號也不可以省略。
try塊里聲明的變量是代碼塊內(nèi)局部變量,它只在try塊內(nèi)有效,在catch塊中不能訪問。
不管try塊中的代碼是否出現(xiàn)異常,也不管哪一個catch塊被執(zhí)行,甚至在try塊或者catch塊中執(zhí)行了return語句,finally塊總會被執(zhí)行。
異常處理語法結(jié)構(gòu)中只有try塊是必需的,也就是說,如果沒有try塊,則不能有后面的catch塊和finally塊,catch塊和finally塊是可選的,但 catch塊和finally塊至少出現(xiàn)其中之一,也可以同時出現(xiàn)多個catch塊,捕獲父類異常的catch塊必需位于捕獲子類異常后面,finally塊必需位于所有catch塊之后。
雖然return語句也強制方法結(jié)束,但一定會先執(zhí)行finally塊里的代碼。如果在異常處理代碼中使用System.exit(1)語句來退出虛擬機,則finally塊將失去執(zhí)行的機會。
通常情況下,不要在finally塊中使用return或者throw等導(dǎo)致方法終止的語句,一旦使用將會導(dǎo)致try塊、catch塊中的retrun、throw語句失效。
當(dāng)java程序執(zhí)行try塊、catch塊時遇到了return 或throw語句,這兩個語句都會導(dǎo)致該方法立即結(jié)束,但是系統(tǒng)執(zhí)行這兩個語句并不會結(jié)束該方法,而是去勛章該異常處理流程中是否包含finally塊,如果沒有程序立即執(zhí)行return或throw語句,方法終止; 如果有finally塊,系統(tǒng)立即開始執(zhí)行finally塊——只有當(dāng)finally塊執(zhí)行完成后,系統(tǒng)才會再次跳回來執(zhí)行try塊、catch塊里的return或throw語句;如果finally塊里也使用return或throw等導(dǎo)致方法終止的語句,finally塊已經(jīng)終止了方法,系統(tǒng)將不會調(diào)回去執(zhí)行try塊、catch塊里的任何代碼 。
下面是一道面試題
public class ThreeException extends Exception{ } public class TestClass { static int count = 0; public static void main(String[] args) { while(true){ try{ if(count++==0) throw new ThreeException(); System.out.println("No Exception"); }catch(ThreeException e){ System.err.println("ThreeException"); }catch(Exception e){ System.err.println("Exception"); }finally{ System.err.println("Finally"); if(count==2) break; } } } }
打印結(jié)果:
ThreeException
Finally
No Exception
Finally
Java異常被分為兩大類:checked異常和Runtime異常(運行時異常)。所有RuntimeException類及其子類的實例被稱為Runtime異常;不是RuntimeException類及其子類的異常實例則被稱為checked異常。
對于checked異常的處理方式有如下兩種:
1、當(dāng)前方法明確知道如何處理該異常,程序應(yīng)該使用try...catch塊來捕獲該異常,然后在對應(yīng)的catch塊中修復(fù)該異常
2、當(dāng)前方法不知道如何處理這種異常,應(yīng)該在定義該方法時聲明拋出該異常。
使用throws聲明拋出異常的思路是,當(dāng)前方法不知道如何處理這種類型的異常,該異常應(yīng)該由上一級調(diào)用者處理,如果main方法也不知道如何處理這種類型的異常,也可以 使用throws聲明拋出異常,該異常交給JVM處理。
JVM對異常處理的方法是打印異常的跟蹤棧信息,并中止程序運行,這就是前面程序在遇到異常后自動結(jié)束的原因。
如果某段代碼中調(diào)用了一個帶throws聲明的方法,該方法聲明拋出了Checked異常,則表明該方法希望它的調(diào)用者來處理該異常。也就是說,調(diào)用該方法時要么放在try塊中顯示捕獲該異常,要么放在另一個帶throws聲明拋出的方法中。
使用throws聲明拋出異常時有一個限制,就是方法重寫時“兩小”中的一條規(guī)則: 子類方法聲明拋出的異常類型應(yīng)該是父類方法聲明拋出的異常類型的子類或相同,子類方法聲明拋出的異常不允許比父類方法聲明拋出的異常多。
如果需要在程序中自行拋出異常,則應(yīng)該使用throw語句,throw語句可以單獨使用,throw語句拋出的不是異常類,而是一個異常實例,而且每次只能拋出一個異常實例。
當(dāng)java運行時接受到用戶自行拋出的異常時,同樣會中止當(dāng)前的執(zhí)行流,跳到該異常對應(yīng)的catch塊,有該catch塊來處理該異常。也就是說,不管是系統(tǒng)自動拋出異常,還是程序員手動拋出的異常,java運行時環(huán)境對異常的處理沒有任何差別。
package com.hb.exception; public class ThrowTest { public static void main(String[]args){ System.out.println("ddd"); try{ //調(diào)用聲明拋出Checked異常的方法,要么顯示捕獲該異常 //要么在main方法中再次聲明拋出 throwChecked(2); }catch(Exception e){ System.out.println(e.getMessage()); } //調(diào)用聲明拋出Runtime異常的方法既可以顯示捕獲該異常,也可以不理會該異常 throwRuntime(3); } public static void throwChecked(int a) throws Exception{ if(a > 0){ //自行拋出Exception 異常 //該代碼必須處于try塊里,或出于帶throws聲明的方法中 throw new Exception("a的值大于0,不符合要求"); } } public static void throwRuntime(int a){ if(a > 0){ // 自行拋出RuntimeException異常,既可以顯示捕獲該異常 // 也可完全不理會該異常,把該異常交給該方法調(diào)用者處理 throw new RuntimeException("a的值大于0,不符合要求"); } } }
用戶自定義異常都應(yīng)該繼承Exception基類,如果希望自定義Runtime異常,則應(yīng)該繼承RuntimeException基類。定義異常類時通常需要提供兩個構(gòu)造器:一個是無參數(shù)的構(gòu)造器;另一個是帶一個字符串參數(shù)的構(gòu)造器,這個字符串將作為該異常對象的描述信息(也就是異常對象的getMessage()方法返回的值)。
public class MyException extends Exception{ //無參數(shù)的構(gòu)造器 public MyException(){} //帶一個字符串參數(shù)的構(gòu)造器 public MyException(String msg){ super(msg); } }
如果需要自定義Runtime異常,只需要將繼承類Exception改為RuntimeException基類即可。
雖然printStackTrace()方法可以很方便地用于追蹤異常的發(fā)生情況,可以用它來調(diào)試程序,但是在最后發(fā)布的程序中,應(yīng)該避免使用它;而應(yīng)該對捕獲的異常進(jìn)行適當(dāng)?shù)奶幚恚皇呛唵蔚貙惓5母櫁P畔⒋蛴〕鰜怼?
必須指出:異常處理機制的初衷是將不可預(yù)料的異常處理代碼和正常的業(yè)務(wù)邏輯處理分離,因此絕不要使用異常處理來替代正常的業(yè)務(wù)邏輯判斷。
異常機制的效率比正常流程控制效率差,所以不要使用異常處理來替代正常的程序流程控制。
把捕獲一個異常然后接著拋出另一個異常,并把原始異常信息保存下來是一種典型的鏈?zhǔn)教幚恚脖环Q為“異常鏈”。
這種把原始異常信息隱藏起來,僅向上提供必要的異常提示信息的處理方式,可以保證底層異常不會擴散到表現(xiàn)層,可以避免向上暴露太多的實現(xiàn)細(xì)節(jié),這完全符合面向獨享的封裝原則
不要使用過于龐大的try塊:
try塊里的代碼過于龐大導(dǎo)致業(yè)務(wù)過于復(fù)雜,會造成try塊中出現(xiàn)異常的可能性大大增加,從而導(dǎo)致分析異常原因的難度也加大,緊隨后面的catch塊才可以針對不同的處理邏輯關(guān)系難度也加大,反而增加了編程復(fù)雜度。
正確做法是將大塊的try塊分割成多個可能出現(xiàn)異常的程序段落,并把他們房子單獨的try塊中,從而分別捕獲并處理異常。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
