發生異常時的流程控制
代碼段發生異常的情況是比較復雜的,有些代碼段只會發生一種異常,而有些代碼會發生多種異常, 有些工作不管代碼段有沒有發生異常都必須進行處理。下面我們來看一下Java語言如何對這些不同情況進 行處理。
(1)使用try…catch
程序運行產生異常時,將從異常發生點中斷程序並向外拋出異常信息。程序通過try…catch可以捕獲 發生的異常,並做出相應的處理,下面我們來看一段異常處理的代碼,如代碼清單2-55所示。
代碼清單2-55 異常處理
1.int x = (int)(Math.random()*5);
2.int y = (int)(Math.random()*10);
3. int[] z = new int[5];
4.try
5.{
6. System.out.println("y/x ="+(y/x));
7 . System.out.println("y ="+y+" z[y]="+z[y]);
8.}
9.catch (ArithmeticException ex1)
10.{
11. System.out.println("算術運算異常:"+ex1.getMessage());
12.}
13.catch (ArrayIndexOutOfBoundsException ex2)
14.{
15. System.out.println(" 數據越界異常:"+ex2.getMessage());
16.}
這個例子中第6行可能會發生被0除的異常,而第7行會發生數組越界的異常。當x為0時,程序將拋出 ArithmeticException異常,當y值大於 4時,程序將拋出ArrayIndexOut- OfBoundsException異常。在 try{}代碼塊中發生的異常時被catch中相應的異常處理塊捕獲,並獲得相應的異常處理。
值得說明的是ArithmeticException和ArrayIndexOutOfBoundsException都是屬於“運行期異常”,如 果不用 try…catch…對它們進行處理,程序也是可以通過編譯的,如果這兩個異常屬性“檢查性異常” 則一定要用try…catch…對它們進行處理。
try 塊中發生異常後,在發生異常代碼行後的其他代碼將被跳過,不予處理,流程直接到達相匹配的 catch異常處理塊。所以當x=0時,第6行代碼發生 ArithmeticException異常,第7行的代碼將被跳過,程 序進入第9~12行的異常處理塊,然後直接到達第16行的後面。
(2)使用finally
異常的處理一般還會有另外的一個部分,那就是finally塊,如果你把一個finally塊放到try塊和 catch塊的後面,當程序運行到try塊後,則無論如何(除了某些極特殊的情況外)finally塊都會得到執 行。
如果try塊產生了異常,則finally塊將在執行了相應的catch異常捕捉塊後得以執行;如果try塊沒有 發生異常,則finally塊將在try塊代碼執行完後執行;如果try塊發生異常,且沒有對應該異常的catch的 塊,則finally將馬上執行。
在以下特殊情況下,finally塊不會被執行:
— 在finally塊中發生了異常;
— 程序所在的線程死亡;
— 在前面的代碼中用System.exit()退出運行;
— 關閉CPU。
(3)多個異常的捕捉處理
當定義了catch塊時,該塊將會捕獲指定異常類的所有異常,包括該異常的所有子類異常,用這種方法 ,可以在一個catch塊中處理一個歸於某一類別的所有異常。如果你為子類的異常指定了一個特定的 catch處理塊,而父類的異常放在另外一個catch塊中,你將能夠更精確地處理多個異常。在這種情況下, 需要滿足這樣的處理規則:子類異常的處理塊必須在父類異常的處理塊之前,否則會發生編譯錯誤,所以 ,越“特殊”的異常越在前面處理,越“普遍”的異常越在後面處理。請看下面的異常處理塊,如代碼清 單 2-56所示。
代碼清單2-56 處理多個可能的異常
1.try
2.{
3. //會引發異常的代碼
4.}
5.catch (GrandchildException e1){
6. //處理異常
7.}
8.catch(ChildException e2) {
9. //處理異常
10.}
11.catch(ParentException e1){
12. //處理異常
13.}
在上例中三個異常的繼承關系為:GrandchildException->ChildException-> Parent Exception。