今天我給大家講解一下java的的錯誤和異常處理機制以及相關異常的執行順序問題。如有不足的地方,歡迎批評指正~
1、首相簡單介紹一下java中的錯誤(Error)和異常(Exception)
錯誤和異常的介紹:
在java.lang軟件包中有一個java.lang.Throwable類,這個類是java中所有錯誤和異常的超類。
在java中錯誤和異常的繼承主要有兩個: 分別為Error和Exception 這兩個。
Error: 是java中所有錯誤類的父類,就是jvm出現錯誤,以及系統蹦潰等現象,這些錯誤沒辦法通過程序來處理,對於系統錯誤,一般不需要開發
人員處理(也無法處理), 比如內存溢出(Out of Memory)和線程死鎖等系統問題。所以在程序中需要使用catch來捕捉處理這類的錯誤或者使用throw來拋出相
關的異常。
Exception: 又可以分為checkedException(編譯時異常) 和RuntimeException(運行時異常) 這兩種異常,checkedException異常在進行編譯的
時候就可以知道會不會發生異常,如果不對這些異常進行拋出、捕獲的話就不能通過編譯,如在使用java的io讀取文件的時候,可能會會出現
所讀取的文件不存在的情況 對於,對於這類編譯時的異常必須手動去處理它們(捕獲或者拋出)。否則的話是無法正常通過編譯器的。 而
RuntimeException就是運行的時候出現的異常,在之前你是沒辦法確定是不是會出現異常。這類異常僅僅在程序運行的過程中才會發現。
比如數組下標越界(ArrayIndexOutOfBoundsException),強制轉換報錯(ClassCastException,一部分),空指針異常(NullPointerException)
除數為零(/ by zero) 對於這類運行時的異常是否拋出, 由用戶根據自身的情況 決定是否拋出異常。java並不強制要求用戶 一定處理。
2、異常處理過程
把會出現異常的程序段放在try中,當拋出異常的時候就會在系統中生成一個異常對象,然后進行查找捕獲這個異常,然后進行處理這個異常,處理之后接着執行下面的程序。
出現異常之后如果沒有進行捕獲處理系統就會直接將這個異常棧的跟蹤信息直接打印出來之后就結束這個程序的執行。
對於異常的處理方式有兩種分別為:try{}catch{}finally{}和throws下面簡單說一下這兩者的區別和聯系
請先看下面的例子:
public class Test{ public static void main(String[] args){ Test2 test2 = new Test2(); try{ System.out.println("invoke the method begin!"); test2.method(); System.out.println("invoke the method end!"); }catch(Exception e){ System.out.println("catch Exception!"); } } } class Test2{ public void method() throws Exception{ System.out.println("method begin!"); int a = 10; int b = 0; int c = a/b; System.out.println("method end!"); } } 很明顯,答案出來了: invoke the method begin! method begin! catch Exception!
對於try{}catch{}finally{}而言,用戶可能確定知道代碼會出現相關的異常,把有可能出現問題的地方放到try中去執行,如果一旦出現異常,立刻終止當前代碼的繼續
執行,轉而去執行catch{}里面的內容。對於這類異常用戶已經處理了,不會在向上拋出。
對於throws而言,一般使用在方法名的后面,使用throws關鍵字的時候,一般是開發者不確定出現什么異常或者出現異常的情況可能有多種。這時開發者在方法后面加 throws關鍵字拋出相關的異常。對於調用該方法的其它開發者者必須捕獲這個異常或者繼續throws這個異常,把這個異常傳遞下去,交給其對應的父類去處理。
需要注意throw關鍵字和throws關鍵字是有區別的。throw一般用於方法中,拋出用戶自定義的異常如 throw new MyException("用戶自定義異常")。
而throws是用在方法名的后面,通知使用該方法的人,當前方法有可能拋出異常。
如果簡單的理解可以這樣看:對於throws可以理解為拋出,拋出給別人,自己不處理。而try{}catch{}finally{}則可以理解為截斷,開發者自己處理這個異常。
3、異常處理的執行順序(針對try{}catch{}finally{}而言)
對於try{}catch{}finally{}而言,,它們的執行順序很簡單,如果在try{}中捕獲相應的異常,中斷當前代碼的執行,轉而去執行catch{}中的內容,最后去執行
finally{}中方法,一般來說finally中的方法都是會被執行的,其中finally中很大程度上用於資源的釋放。
下面講解一些我們java程序員需要注意的地方。
a、finally中的代碼總是會執行嗎?
答:no,如果一個方法內在執行try{}語句之前就已經return了,那么finally語句指定不會執行了。因為它根本沒有進入try語句中
如果在一個try語句中調用System.exit(0);方法,那么就會退出當前java虛擬機,那么finally也就沒有執行的機會了。
b、finally在return之前執行還是在return之后執行?
答:很多人可能會說在return執行之前執行。我的答案是在return中間執行,是不是很特別,請按下面的例子:
package com.yonyou.test; class Test{ public static void main(String[] args) { System.out.println(method()); } public static int method(){ int x=1; try{ return x; }catch(Exception e) { return 0; }finally{ ++x; } } }
請問輸出的結果是多少呢?
正確答案是:1
下面我來講解一下這個程序的執行過程,
首先程序在執行到try{}語句中的return方法后,就會先返回相應的值,並把相應的值存儲在一個臨時棧中去保存這個結果。這時臨時棧中存儲的值為1。
但是程序不會立刻返回,轉而回去執行finally中的方法,++x,在finally執行完后,方法全部執行完,這時會再次調用return方法,注意這時
不在是返回值,而是告訴主調程序,被調程序已經執行完了,你可以接着去執行你主程序的其它方法了。但是請注意,此時返回的值還是原來保存在臨時
棧中的值1。
為了更好的理解這個問題,我們看下面的程序:
package com.yonyou.test; class Test{ public static void main(String[] args) { System.out.println(method()); } public static int method(){ try{ return 1; }catch(Exception e) { return 0; }finally{ return 2; } } }
這時的正確答案又是多少呢?
沒錯是2,這里僅僅需要注意的是在try{}語句中執行到return 1 會在臨時棧中存儲值為1的變量。接着回去執行finally里面的內容,這時執行finally中的return 2;方法,這時
臨時棧中的值就是變為 2,會覆蓋原來臨時棧中的值1.所以它的返回值為2。
c、finally方法是必須的嗎?
不是,開發者可以根據自身的情況去決定是否使用finally關鍵字。
好吧,今天就先到這里吧。