之前,在使用異常捕獲語句try...catch...throw語句時,一直沒太留意幾種用法的區別,前幾天調試程序時無意中了解到幾種使用方法是有區別的,網上一查,還真是,主要是區別在堆棧信息的起始點不同。總結如下:
一、異常處理過程
異常是發生在函數域的,函數內部發生異常:
1. 如果有try-catch處理,則跳到catch處理完畢,再繼續執行catch后面的語句塊。
2. 如果沒有異常處理,則往上拋。如果調用方也沒有異常處理,則繼續往函數棧上拋,直到最外層函數,如果應用程序級別也沒有處理,則由操作系統捕獲到程序發生錯誤,結束程序
throw ex;會將到現在為止的所有信息清空,認為你catch到的異常已經被處理了,只不過處理過程中又拋出新的異常,從而找不到真正的錯誤源。X
throw new Exception("errstr",ex);經過對異常重新包裝,會保留原始異常點信息。推薦位置1
三、try catch finally的執行順序(有return的情況下)
結論:
1、不管有木有出現異常,finally塊中代碼都會執行;
2、當try和catch中有return時,finally仍然會執行;
3、finally是在return后面的表達式運算后執行的(此時並沒有返回運算后的值,而是先把要返回的值保存起來,管finally中的代碼怎么樣,返回的值都不會改變,任然是之前保存的值),所以函數返回值是在finally執行前確定的;
4、finally中最好不要包含return,否則程序會提前退出,返回值不是try或catch中保存的返回值。
四、throw例子:
第一種(不推薦使用,可惜很多人都一直這么用的,包括俺,嘻嘻),這樣適用會吃掉原始異常點,重置堆棧中的異常起始點:

try { } catch (Exception ex) { throw ex; }
第二種,可追溯到原始異常點,不過編譯器會警告,定義的ex未有使用:

try { } catch (Exception ex) { throw; }
第三種,不帶異常參數的,這個同第二種其實一樣,可捕獲所有類型的異常,IDE不會告警:

try { } catch { throw; }
其實第二種和第三種用法,書上也是不建議使用的,一般要從小粒度的異常捕獲開始,采用多個catch語句,大家就見仁見智吧。。。
第四種:經過對異常重新包裝,但是會保留原始異常點信息。推薦使用。

try { } catch (Exception ex) { throw new Exception("經過進一步包裝的異常", ex); }
下面用個例子來加以說明:

1 /// <summary> 2 /// 入口方法 3 /// </summary> 4 public static void Main() 5 { 6 ExceptionClass ec = new ExceptionClass(); 7 8 try 9 { 10 ec.ExceptionThrow1(); 11 } 12 catch (Exception ex) 13 { 14 Console.WriteLine(ex.ToString()); 15 } 16 17 Console.WriteLine("---------------------------------------------------------------------"); 18 19 try 20 { 21 ec.ExceptionThrow2(); 22 } 23 catch (Exception ex) 24 { 25 Console.WriteLine(ex.ToString()); 26 } 27 28 Console.WriteLine("---------------------------------------------------------------------"); 29 30 try 31 { 32 ec.ExceptionThrow3(); 33 } 34 catch (Exception ex) 35 { 36 Console.WriteLine(ex.ToString()); 37 } 38 39 Console.WriteLine("---------------------------------------------------------------------"); 40 41 try 42 { 43 ec.ExceptionThrow4(); 44 } 45 catch (Exception ex) 46 { 47 Console.WriteLine(ex.ToString()); 48 } 49 50 Console.WriteLine("---------------------------------------------------------------------"); 51 52 Console.ReadKey(); 53 } 54 } 55 56 /// <summary> 57 /// 該Class用來測試異常拋出時相關上下文棧的調用情況 58 /// </summary> 59 public class ExceptionClass 60 { 61 /// <summary> 62 /// 拋出異常方法 63 /// </summary> 64 public void ExceptionThrow1() 65 { 66 try 67 { 68 // 調用原始異常拋出方法來拋出異常 69 this.ExceptionMethod(); 70 } 71 catch (Exception ex) 72 { 73 throw ex; 74 } 75 } 76 77 /// <summary> 78 /// 拋出異常方法1 79 /// </summary> 80 public void ExceptionThrow2() 81 { 82 try 83 { 84 this.ExceptionMethod(); 85 } 86 catch (Exception ex) 87 { 88 throw; 89 } 90 } 91 92 /// <summary> 93 /// 拋出異常方法2 94 /// </summary> 95 public void ExceptionThrow3() 96 { 97 try 98 { 99 this.ExceptionMethod(); 100 } 101 catch 102 { 103 throw; 104 } 105 } 106 107 /// <summary> 108 /// 拋出異常方法3 109 /// </summary> 110 public void ExceptionThrow4() 111 { 112 try 113 { 114 this.ExceptionMethod(); 115 } 116 catch (Exception ex) 117 { 118 throw new Exception("經過進一步包裝的異常", ex); 119 } 120 } 121 122 /// <summary> 123 /// 原始異常拋出方法 124 /// </summary> 125 private void ExceptionMethod() 126 { 127 throw new DivideByZeroException(); 128 } 129 }
運行結果如下:
從運行的結果可以看到,第一種用法已經吃掉了原始異常信息。而其它3種用法都可以追溯到原始異常,推薦使用第四種用法,希望大家能了解這些細微的差別,享受Coding的樂趣吧...
五、try catch finally 舉例:
情況1:try{} catch(){}finally{} return;
顯然程序按順序執行。
情況2:try{ return; }catch(){} finally{} return;
程序執行try塊中return之前(包括return語句中的表達式運算)代碼;
再執行finally塊,最后執行try中return;
finally塊之后的語句return,因為程序在try中已經return所以不再執行。
情況3:try{ } catch(){return;} finally{} return;
程序先執行try,如果遇到異常執行catch塊,
有異常:則執行catch中return之前(包括return語句中的表達式運算)代碼,再執行finally語句中全部代碼,
最后執行catch塊中return. finally之后也就是4處的代碼不再執行。
無異常:執行完try再finally再return.
情況4:try{ return; }catch(){} finally{return;}
程序執行try塊中return之前(包括return語句中的表達式運算)代碼;
再執行finally塊,因為finally塊中有return所以提前退出。
情況5:try{} catch(){return;}finally{return;}
程序執行catch塊中return之前(包括return語句中的表達式運算)代碼;
再執行finally塊,因為finally塊中有return所以提前退出。
情況6:try{ return;}catch(){return;} finally{return;}
程序執行try塊中return之前(包括return語句中的表達式運算)代碼;
有異常:執行catch塊中return之前(包括return語句中的表達式運算)代碼;
則再執行finally塊,因為finally塊中有return所以提前退出。
無異常:則再執行finally塊,因為finally塊中有return所以提前退出。
最終結論:任何執行try 或者catch中的return語句之前,都會先執行finally語句,如果finally存在的話。
如果finally中有return語句,那么程序就return了,所以finally中的return是一定會被return的,
編譯器把finally中的return實現為一個warning。
下面是個測試程序 public class FinallyTest { public static void main(String[] args) { System.out.println(new FinallyTest().test());; } static int test() { int x = 1; try { x++; return x; } finally { ++x; } } } 結果是2。
分析: