今天,看到一個面試題:
try-catch-finally 中,如果 catch 中 return 了,finally 還會執行嗎?
我們用代碼來驗證下:
public static void main(String[] args) { System.out.println("我是輸出結果a:" + test1()); public static int test1() { int a = 5; try { System.out.println(a / 0); a = 10; } catch (ArithmeticException e) { System.out.println("我是catch中的a:" + a); return a = 20;// 程序執行到這時,a=20已經執行完,准備好返回結果了,發現有finally,則在去執行finally } finally { System.out.println("我是finally中未重定義的a:" + a); a = 30; System.out.println("我是finally中重定義過的a:" + a); } return a; }
運行結果:
1 我是catch中的a:5 2 我是finally中未重定義的a:20 3 我是finally中重定義過的a:30 4 我是輸出結果a:20
從結果中可看出:即使catch中return了,finally中的代碼還是會執行。但是有個問題,明明結果顯示,經過finally代碼的執行,a已經是30了,返回結果為什么還是20?
我們再執行另外代碼:
1 public static void main(String[] args) { 2 System.out.println("我是輸出結果a:" + test1()); 3 4 } 5 6 public static int test1() { 7 int a = 5; 8 try { 9 System.out.println(a / 0); 10 a = 10; 11 } catch (ArithmeticException e) { 12 System.out.println("我是catch中的a:" + a); 13 return a = 20;// 程序執行到這時,a=20已經執行完,准備好返回結果了,發現有finally,則在去執行finally 14 } finally { 15 System.out.println("我是finally中未重定義的a:" + a); 16 a = 30; 17 System.out.println("我是finally中重定義過的a:" + a); 18 return a = 30; 19 } 20 }
運行結果:
1 我是catch中的a:5 2 我是finally中未重定義的a:20 3 我是finally中重定義過的a:30 4 我是輸出結果a:30
我們會發現,如果finally中有return,結果會根據finally中的結果返回,如果finally中沒有return,結果會按照catch的結果返回,但是不管怎么樣,都是會執行finally的代碼。
前面的例子是基本類型的,那我們看下引用類型是不是也這樣:
1 public static User getName1(){ 2 User user = null; 3 try { 4 user = new User("張三"); 5 throw new Exception(); 6 } catch (Exception e) { 7 user = new User("李四"); 8 return user; 9 } finally { 10 user = new User("王五"); 11 //return user; 12 } 13 }
結果
User [name=李四]
再試下其他:
1 public static User getName1(){ 2 User user = null; 3 try { 4 user = new User("張三"); 5 throw new Exception(); 6 } catch (Exception e) { 7 user = new User("李四"); 8 return user; 9 } finally { 10 user = new User("王五"); 11 return user; 12 } 13 }
結果:
1 User [name=王五]
額。。。。。。引用類型類型好像也是這樣的。
我們再看看:
1 public static User getName2(){ 2 User user = null; 3 try { 4 user = new User("張三"); 5 throw new Exception(); 6 } catch (Exception e) { 7 user.setName("李四"); 8 return user; 9 } finally { 10 user.setName("王五"); 11 //return user; 12 } 13 }
結果如下:
User [name=王五]
額。。。。好像不對啊,不應該是李四嗎?
1 public static User getName2(){ 2 User user = null; 3 try { 4 user = new User("張三"); 5 throw new Exception(); 6 } catch (Exception e) { 7 user.setName("李四"); 8 return user; 9 } finally { 10 user.setName("王五"); 11 return user; 12 } 13 }
結果:
User [name=王五]
引用類型好像有問題啊。。。。
其實可以這么理解:執行完catch內的代碼后,會把結果值暫時保存,然后執行finally中的代碼,如果finally中沒有return,則直接把保存的值返回。如果finally中有return,則值會被finally改變,再返回。
而如果finally中沒有return,返回的值好像也有部分出乎我們的意料。可以這樣理解吧,catch中的結果值會被final修飾,當final修飾一個基本數據類型時,表示該基本數據類型的值一旦在初始化后便不能發生變
化;如果final修飾一個引用類型時,則在對其初始化之后便不能再讓其指向其他對象了,但該引用所指向的對象的內容是可以發生變化的。
就那下面代碼來說明:
1 User u1 = new User("張三"); 2 User u2 = new User("李四"); 3 final User u3 = u1; 4 u3 = u2;//這行代碼會報編譯錯誤 5 System.out.println(u3); 6 u1.setName("王五"); 7 System.out.println(u3);
第四行代碼會報編譯錯誤:The final local variable u3 cannot be assigned. It must be blank and not using a compound assignment
說明final修飾的不能改變引用對象,但是引用對象u1的值變化還是可以。
上面的代碼執行下:
User [name=張三]
User [name=王五]
現在可以看出 上面的代碼 user.setName("王五");和user = new User("王五"); 執行的結果為什么會不一樣,因為setname改變的是引用所指向的對象的內容,是可以的。= new User("王五"); 是改變了引用指向,是不可以的。