標籤:
try-catch語句還可以包括第三部分,就是finally子句。它表示無論是否出現異常,都應當執行的內容。try-catch-finally語句的一般文法形式為:
try { // 可能會發生異常的程式碼 } catch (Type1 id1) { // 捕獲並處理try拋出的異常類型Type1 } catch (Type2 id2) { // 捕獲並處理try拋出的異常類型Type2 } finally { // 無論是否發生異常,都將執行的語句塊 }
帶finally子句的例外處理常式。
public class TestException { public static void main(String args[]) { int i = 0; String greetings[] = { " Hello world !", " Hello World !! ", " HELLO WORLD !!!" }; while (i < 4) { try { // 特別注意迴圈控制變數i的設計,避免造成無限迴圈 System.out.println(greetings[i++]); } catch (ArrayIndexOutOfBoundsException e) { System.out.println("數組下標越界異常"); } finally { System.out.println("--------------------------"); } } } }
運行結果:
Hello world !--------------------------Hello World !!--------------------------HELLO WORLD !!!--------------------------數組下標越界異常--------------------------
在例5中,請特別注意try子句中語句塊的設計,如果設計為如下,將會出現死迴圈。如果設計為:
try { System.out.println (greetings[i]); i++; }
try 塊:用於捕獲異常。其後可接零個或多個catch塊,如果沒有catch塊,則必須跟一個finally塊。
catch 塊:用於處理try捕獲到的異常。
finally 塊:無論是否捕獲或處理異常,finally塊裡的語句都會被執行。當在try塊或catch塊中遇到return語句時,finally語句塊將在方法返回之前被執行。在以下4種特殊情況下,finally塊不會被執行:
1)在finally語句塊中發生了異常。2)在前面的代碼中用了System.exit()退出程式。3)程式所在的線程死亡。4)關閉CPU。
try-catch-finally 規則(
異常處理語句的文法規則
):
1) 必須在 try 之後添加 catch 或 finally 塊。try 塊後可同時接 catch 和 finally 塊,但至少有一個塊。
2) 必須遵循塊順序:若代碼同時使用 catch 和 finally 塊,則必須將 catch 塊放在 try 塊之後。
3) catch 塊與相應的異常類的類型相關。
4) 一個 try 塊可能有多個 catch 塊。若如此,則執行第一個匹配塊。即Java虛擬機器會把實際拋出的異常對象依次和各個catch代碼塊聲明的異常類型匹配,如果異常對象為某個異常類型或其子類的執行個體,就執行這個catch代碼塊,不會再執行其他的 catch代碼塊
5) 可嵌套 try-catch-finally 結構。
6) 在 try-catch-finally 結構中,可重新拋出異常。
7) 除了下列情況,總將執行 finally 做為結束:JVM 過早終止(調用 System.exit(int));在 finally 塊中拋出一個未處理的異常;電腦斷電、失火、或遭遇病毒攻擊。
try、catch、finally語句塊的執行順序:
1)當try沒有捕獲到異常時:try語句塊中的語句逐一被執行,程式將跳過catch語句塊,執行finally語句塊和其後的語句;
2)當try捕獲到異常,catch語句塊裡沒有處理此異常的情況:當try語句塊裡的某條語句出現異常時,而沒有處理此異常的catch語句塊時,此異常將會拋給JVM處理,finally語句塊裡的語句還是會被執行,但finally語句塊後的語句不會被執行;
3)當try捕獲到異常,catch語句塊裡有處理此異常的情況:在try語句塊中是按照順序來執行的,當執行到某一條語句出現異常時,程式將跳到catch語句塊,並與catch語句塊逐一匹配,找到與之對應的處理常式,其他的catch語句塊將不會被執行,而try語句塊中,出現異常之後的語句也不會被執行,catch語句塊執行完後,執行finally語句塊裡的語句,最後執行finally語句塊後的語句;
測試finally執行影響情況
不影響返回結果,主要還是try中返回了,在後面只會執行一下finally,即使name改變也不會影響返回結果
public static void main(String[] args) { System.out.println(get("")); } public static String get(String name) { try { System.out.println("try x"+name); name = name.toLowerCase()+"123456"; System.out.println("try y"+name); return name; } catch (Exception e) { System.out.println("exception"+name); }finally { name = "----"; } System.out.println("return"+name); return "```"; }
結果
try xtry y123456123456
會影響傳回值的情況(本列測試,也正好測試了return返回的如果是對象的引用不是基礎資料型別 (Elementary Data Type)的資料的話,則finally中如果將對象中的內容改變,return中的內容也將會改變,也即是對象在記憶體中所指向的字元)
public static void main(String[] args) { System.out.println(get(new StringBuilder()).toString()); } public static StringBuilder get(StringBuilder name) { try { System.out.println("try x"+name); name.append("123456"); System.out.println("try y"+name); return name; } catch (Exception e) { System.out.println("exception"+name); }finally { name .append("-----"); } System.out.println("return"+name); return name; }
結果
try xtry y123456123456-----
會影響傳回值的情況(主要為finally中執行了return所以被迫影響到了try中的return)
public static void main(String[] args) { System.out.println(get("")); } public static String get(String name) { try { System.out.println("try x"+name); name = name.toLowerCase()+"123456"; System.out.println("try y"+name); return name; } catch (Exception e) { System.out.println("exception"+name); }finally { name = "----"; System.out.println("finally"+name); return "這列"; } //System.out.println("return"+name); //return "```"; }
輸出(從結果看很明顯將原版返回123456的結果被finally的return返回了)
try xtry y123456finally----這列
Java-try-catch-finally