1. 程式人生 > >JAVA面試常問知識總結(一)

JAVA面試常問知識總結(一)

try catch finally 的詳細用法:

 1 public static  int testBasic(){
 2         int i = 1; 
 3         try{
 4             i++;
 5             System.out.println("try block, i = "+i);
 6         }catch(Exception e){
 7             i ++;
 8             System.out.println("catch block i = "+i);
 9         }finally
{ 10 i = 10; 11 System.out.println("finally block i = "+i); 12 } 13 return i; 14 }

此程式碼為常規程式碼,會按照順序執行,先執行try內程式碼段,沒有異常的話進入finally,最後返回,那麼輸出如下:

try block, i = 2

finally block i = 10  最終返回 i=10;

這個沒有問題,如果我們把return語句放入try catch裡又會怎麼樣呢

 1 public static  int
testBasic(){ 2 int i = 1; 3 try{ 4 i++; 5 System.out.println("try block, i = "+i); 6 return i; 7 }catch(Exception e){ 8 i ++; 9 System.out.println("catch block i = "+i); 10 return i; 11 }finally
{ 12 i = 10; 13 System.out.println("finally block i = "+i); 14 } 15 }

輸出結果為:
try block, i = 2
finally block i = 10    最終返回 i = 2;

程式碼順序執行從try到finally,由於finally是無論如何都會執行的,所以try裡的語句並不會直接返回。在try語句的return塊中,return返回的引用變數並不是try語句外定義的引用變數i,而是系統重新定義了一個區域性引用i’,這個引用指向了引用i對應的值,也就是2,即使在finally語句中把引用i指向了值10,因為return返回的引用已經不是i,而是i',所以引用i的值和try語句中的返回值無關了。

但是,這只是一部分,如果把i換成包裝型別而不是基本型別呢,來看看輸出結果怎樣,示例如下: 

 1 public static  List<Object> testWrap(){
 2         List<Object> list = new ArrayList<>();
 3         try{
 4             list.add("try");
 5             System.out.println("try block");
 6             return list;
 7         }catch(Exception e){
 8             list.add("catch");
 9             System.out.println("catch block");
10             return list;
11         }finally{
12             list.add("finally");
13             System.out.println("finally block ");
14         }
15 }

輸出結果如下:

try block
finally block    最終返回 i = [try, finally]

 可以看到,finally裡對list集合的操作生效了,這是為什麼呢。我們知道基本型別在棧中儲存,而對於非基本型別是儲存在堆中的,返回的是堆中的地址,因此內容被改變了

好了,現在我們在finally里加一個return,看看語句是從哪裡返回的

 1 public static  int testBasic(){
 2         int i = 1; 
 3         try{
 4             i++;
 5             System.out.println("try block, i = "+i);
 6             return i;
 7         }catch(Exception e){
 8             i ++;
 9             System.out.println("catch block i = "+i);
10             return i;
11         }finally{
12             i = 10;
13             System.out.println("finally block i = "+i);
14             return i;
15         }
16 }

輸出結果如下:

try block, i = 2
finally block i = 10
main test i = 10

可以看到,是從finally語句塊中返回的。可見,JVM是忽略了try中的return語句。但IDE中會對finally中加的return有黃色警告提示,這是為什麼呢,在try里加入一行會執行異常的程式碼,如下:

 1 public static  int testBasic(){
 2         int i = 1; 
 3         try{
 4             i++;
 5             int m = i / 0 ;
 6             System.out.println("try block, i = "+i);
 7             return i;
 8         }catch(Exception e){
 9             i ++;
10             System.out.println("catch block i = "+i);
11             return i;
12         }finally{
13             i = 10;
14             System.out.println("finally block i = "+i);
15             return i;
16         }
17 }

列印結果如下:

catch block i = 3
finally block i = 10
main test i = 10

可以看到,因為finally中有return語句,try、catch中的異常被消化掉了,遮蔽了異常的發生,這與初期使用try、catch的初衷是相違背的,因此編譯器也會提示警告。

那如果在finally中有異常發生,會對try、catch中的異常有什麼影響呢?


 1 public static  int testBasic(){
 2         int i = 1; 
 3         try{
 4             i++;
 5             Integer.parseInt(null);
 6             System.out.println("try block, i = "+i);
 7             return i;
 8         }catch(Exception e){
 9             String.valueOf(null);
10             System.out.println("catch block i = "+i);
11             return i;
12         }finally{
13             i = 10;
14             int m = i / 0;
15             System.out.println("finally block i = "+i);
16         }
17 }

這裡我們在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裡的異常資訊即被消化掉了,也達不到異常資訊處理的目的。

總結以上測試:

1、finally語句總會執行

2、如果try、catch中有return語句,finally中沒有return,那麼在finally中修改除包裝型別和靜態變數、全域性變數以外的資料都不會對try、catch中返回的變數有任何的影響(包裝型別、靜態變數會改變、全域性變數

3、儘量不要在finally中使用return語句,如果使用的話,會忽略try、catch中的返回語句,也會忽略try、catch中的異常,遮蔽了錯誤的發生

4、finally中避免再次丟擲異常,一旦finally中發生異常,程式碼執行將會丟擲finally中的異常資訊,try、catch中的異常將被忽略

所以在實際專案中,finally常常是用來關閉流或者資料庫資源的,並不額外做其他操作。