往期回顧:上一篇咱們大體總結了異常的繼承體系,說明了Exception和Error兩個大類都繼承於頂級父類Throwable,又談到編譯時異常與運行時異常的區別,談到異常的處理方式,以及處理方式中關於捕獲方式的幾種類型。
本篇承上啓下,將從異常的其他部分進行總結,可是畢竟如今處於初學階段,未必可以體會異常在真實場景中運用的便利之處,因此本文只是對目前所學內容的概括整理,後續新的體會將會及時更新。java
- 從當前方法開始,沿着方法的調用鏈,按照異常的反向傳播方向找到異常的處理代碼。
- 從第一個到最後一個檢查catch塊,判斷是否相匹配。若是是,那麼恭喜!直接進入catch塊中執行處理異常語句;若是不是,就將該異常傳給方法的調用者,在調用者中繼續執行相同步驟:匹配就處理,不匹配就向上傳……
- 直到最後若是都沒有找到的話,程序將會終止,並在打印臺上打印出錯信息。
若是是相對單一方法而言,實際上是很簡單的;若是方法層層嵌套呢,狀況又是咋樣的呢,我們來驗證一下以上內容:
//主方法 public static void main(String[] args) { try{ //調用m1() m1(); System.out.println("ExceptionMyDemo.main"); }catch (Exception e){ System.out.println("ExceptionMyDemo.main.catch"); } } //m1() private static void m1(){ try{ //調用m2() m2(); System.out.println("ExceptionMyDemo.m1"); }catch (NullPointerException e){ System.out.println("ExceptionMyDemo.m1.catch"); } } //m2() private static void m2(){ String str = null; System.out.println(str.hashCode()); } //測試結果: ExceptionMyDemo.m1.catch ExceptionMyDemo.main
catch (ArithmeticException e)
,這時的測試結果會是這個樣子://更改以後的測試結果: ExceptionMyDemo.main.catch
由於m2()拋出的異常在m1中並無被合適地處理,因此向上拋出,在main方法中找到了處理方法,遂執行處理語句。數組
由於拋出的異常沒人處理,它就會在控制檯上打印異常的棧軌跡,關於拋出的異常信息,咱們接下來進行詳細分析。學習
咱們提到,不管是虛擬機拋出異常仍是咱們主動拋出,異常的錯誤信息都包含其中,以便於咱們得知並更好地處理異常,那麼順着上面所說,咱們剛剛看到的就是異常的棧軌跡:測試
public void printStackTrace()
:默認將該Throwable對象及其調用棧的跟蹤信息打印到標準錯誤流。public String getMessage()
:返回描述異常對象信息的字符串。public String toString()
:異常信息message爲空就返回異常類的全名,不然返回全名:message
的形式。public StackTraceElement[] getStackTrace()
:返回棧跟蹤元素的數組,表示和該異常對象相關的棧的跟蹤信息。名言警句:不管異常是否會發生,finally修飾的子句老是會被執行。spa
因而咱們進行了簡單的嘗試:3d
public static void m2(){ try{ System.out.println("0"); System.out.println(1/0); System.out.println("1"); } catch (Exception e){ System.out.println("2"); } finally { System.out.println("3"); } System.out.println("4"); } //測試結果 0 2 3 4 被打印在控制檯上
System.out.println(1/0);
時發生了異常,因而進入catch塊,finally子句必會被執行,而後執行try語句後的下一條語句。想象如下:假如把接收異常的實例類型改成另一個不匹配的類型的話,也就是說沒法正常捕獲,結果又會如何呢?結果以下:
指針
還有一個注意點就是4也沒有被打印出來,是由於沒有捕獲到異常,將會把異常拋給調用者,因此不會執行System.out.println("4");
。code
可是,化名爲幾千萬個爲何的我又開始疑惑了,咱們直到return能夠將方法直接返回,強制退出。那麼若是在try中使用return語句,finally還會不會不忘初心,繼續執行呢?htm
前方高能!各單位注意!!!
猜猜看,這四個方法執行結果是啥呢?
private static int m1(){ try{ return 1; }catch(Exception e){ } return 2; }
private static int m2(){ try{ return 1; }finally { return 2; } //使用finally子句時能夠省略catch塊 }
private static int m3(){ try{ return 1; }finally { try{ return 2; }finally { return 3; } } }
private static int m4(){ int i = 4; try{ return i++; }finally { i++; } }
答案揭曉:分別是:1,2,3,4。大家猜對了嗎?哈哈……
我想前三個答案應該是毋庸置疑的,可是這第四個就有點離譜了。不是說finally語句必定會執行嗎,執行哪去了呢,你要是執行的話,你i難道不該該變成6了嗎?
額……咳咳,這個嘛,我也有點迷惑,可是通過一番討教,稍微懂了一些:
可是若是進行改變的是引用數據類型的變量時,那麼就會隨之改變了,人家村的是地址,改的就是自己。我在這邊就稍微來個簡單的例子奧:
public static Student m(){ Student s = new Student(); try{ s.age = 20; s.name = "天喬"; return s; }finally { s.name = "巴夏"; s.age = 2; } } //測試結果 //Student{age=2, name='巴夏'}
本文如有敘述不當之處,還望評論區批評指正哦!