在網上看到一些異常處理的面試題,試着總結一下,先看下面代碼,把這個方法在main中進行調用打印返回結果,看看結果輸出什麼。java
public static int testBasic(){ int i = 1; try{ i++; System.out.println("try block, i = "+i); }catch(Exception e){ i ++; System.out.println("catch block i = "+i); }finally{ i = 10; System.out.println("finally block i = "+i); } return i; }
沒錯,會按照順序執行,先執行try內代碼段,沒有異常的話進入finally,最後返回,那麼輸出以下:面試
try block, i = 2
finally block i = 10
main test i = 10數據庫
這個沒有問題,若是咱們把return語句放入try catch裏又會怎麼樣呢測試
public static int testBasic(){ int i = 1; try{ i++; System.out.println("try block, i = "+i); return i; }catch(Exception e){ i ++; System.out.println("catch block i = "+i); return i; }finally{ i = 10; System.out.println("finally block i = "+i); } }
輸出結果是:spa
try block, i = 2
finally block i = 10
main test i = 2code
代碼順序執行從try到finally,因爲finally是不管如何都會執行的,因此try裏的語句並不會直接返回。在try語句的return塊中,return返回的引用變量並非try語句外定義的引用變量i,而是系統從新定義了一個局部引用i’,這個引用指向了引用i對應的值,也就是2,即便在finally語句中把引用i指向了值10,由於return返回的引用已經不是i,而是i',因此引用i的值和try語句中的返回值無關了。blog
可是,這只是一部分,若是把i換成包裝類型而不是基本類型呢,來看看輸出結果怎樣,示例以下:資源
public static List<Object> testWrap(){ List<Object> list = new ArrayList<>(); try{ list.add("try"); System.out.println("try block"); return list; }catch(Exception e){ list.add("catch"); System.out.println("catch block"); return list; }finally{ list.add("finally"); System.out.println("finally block "); } }
打印結果以下:編譯器
try block
finally block
main test i = [try, finally]it
能夠看到,finally裏對list集合的操做生效了,這是爲何呢。咱們知道基本類型在棧中存儲,而對於非基本類型是存儲在堆中的,返回的是堆中的地址,所以內容被改變了。
好了,如今咱們在finally里加一個return,看看語句是從哪裏返回的。
public static int testBasic(){ int i = 1; try{ i++; System.out.println("try block, i = "+i); return i; }catch(Exception e){ i ++; System.out.println("catch block i = "+i); return i; }finally{ i = 10; System.out.println("finally block i = "+i); return i; } }
輸出結果以下:
try block, i = 2
finally block i = 10
main test i = 10
能夠看到,是從finally語句塊中返回的。可見,JVM是忽略了try中的return語句。但IDE中會對finally中加的return有黃色警告提示,這是爲何呢,在try里加入一行會執行異常的代碼,以下:
public static int testBasic(){ int i = 1; try{ i++; int m = i / 0 ; System.out.println("try block, i = "+i); return i; }catch(Exception e){ i ++; System.out.println("catch block i = "+i); return i; }finally{ i = 10; System.out.println("finally block i = "+i); return i; } }
打印結果以下:
catch block i = 3
finally block i = 10
main test i = 10
能夠看到,由於finally中有return語句,try、catch中的異常被消化掉了,屏蔽了異常的發生,這與初期使用try、catch的初衷是相違背的,所以編譯器也會提示警告。
那若是在finally中有異常發生,會對try、catch中的異常有什麼影響呢?
public static int testBasic(){ int i = 1; try{ i++; Integer.parseInt(null); System.out.println("try block, i = "+i); return i; }catch(Exception e){ String.valueOf(null); System.out.println("catch block i = "+i); return i; }finally{ i = 10; int m = i / 0; System.out.println("finally block i = "+i); } }
這裏咱們在try、catch裏強行加上異常語句,打印結果以下:
Exception in thread "main" java.lang.ArithmeticException: / by zero
at tryandcatch.TryAndCatch.testBasic(TryAndCatch.java:25)
at tryandcatch.TryAndCatch.main(TryAndCatch.java:45)
這個提示表示的是finally裏的異常信息,也就是說一旦finally裏發生異常,try、catch裏的異常信息即被消化掉了,也達不到異常信息處理的目的。
總結以上測試:
一、finally語句總會執行
二、若是try、catch中有return語句,finally中沒有return,那麼在finally中修改除包裝類型和靜態變量、全局變量之外的數據都不會對try、catch中返回的變量有任何的影響(包裝類型、靜態變量會改變、全局變量)
三、儘可能不要在finally中使用return語句,若是使用的話,會忽略try、catch中的返回語句,也會忽略try、catch中的異常,屏蔽了錯誤的發生
四、finally中避免再次拋出異常,一旦finally中發生異常,代碼執行將會拋出finally中的異常信息,try、catch中的異常將被忽略
因此在實際項目中,finally經常是用來關閉流或者數據庫資源的,並不額外作其餘操做。