由一道面試題想到的:Finally

找工做時,有這樣一道題:spa

try{}裏面有一條return語句,那麼緊跟在這個try後的finally{}裏的代碼會不會執行,何時執行,在return以前仍是以後?code

我沒有怎麼思考,根據腦子裏僅有的一點異常知識,給出了下面的解:blog

若是try{}沒有拋出異常,那麼finally{}裏的代碼不會執行。進程

若是try{}拋出異常,那麼finally{}裏的代碼會執行,在return以前。內存

藉助下面的代碼驗證一下:資源

1 private static int testFinally() {
2     try {
3         System.out.println("Try!");
4         return 1;
5     } finally {
6         System.out.println("Finally!");
7     }
8 }        

毫無疑問,輸出的結果顯示上述解是草率的,是錯的。那麼,正解是什麼?其實,讀書用心點的話,能夠注意到《Core Java》上的這段話:源碼

Suppose you exit the middle of a try block with a return statement. Before the method returns, the finally block is executed. If the finally block also contains a return statement, then it masks the original return value.虛擬機

——摘自《Core Java, Volume I: Fundamentals》it

這段話就是正解。當方法中拋出異常,或包含break,continue,return語句時,方法就沒法按照正常的方式終止。通常地,在try-finally結構中,當try部分意外終止時,並不意味着結束,方法仍然會繼續執行finally部分。也就是說,上述代碼返回1以前,會先打印「Finally!」。若是問緣由,真說不出什麼,沒什麼道理,Java就是這麼幹的。就和學英語遇到陌生的詞組解釋不了時,用「固定搭配」來安慰本身,是同一個道理。io

進一步地,有沒有某種狀況,finally{}不會執行?另外一個例子:

1 private static void testFinally() {
2     try {
3         System.out.println("Try!");
4         System.exit(0);
5     } finally {
6         System.out.println("Finally!");
7     }
8 }   

System.exit(0)能夠阻止執行finally語句塊。之因此能夠作到,是由於System.exit()方法會當即終止當前正在運行的 Java 虛擬機。咱們知道,在Java中,源碼首先被編譯成字節碼,而後由虛擬機解釋執行class文件。虛擬機進程被殺死後,程序固然沒法接着執行下去。

衆所周知,在須要關閉一些資源時,使用Finally語句是一種不錯的選擇。下面介紹一種結合try-catch和try-finally的方式:

 1 InputStream in = ...;
 2 try{
 3     try{
 4        // [1]Code may throw excption.
 5     }finally{
 6        in.close();  //[2]
 7     }
 8 }catch(IOException e){
 9     // [3]handle exception.
10 }

在這種方式中,內存的try語句塊只有一個職責,就是關閉輸入流。外層的try語句塊也只有一個職責,就是捕獲可能出現的異常。職責至關明確,結構至關清晰。可是,這種方式也存在潛在的錯誤:若是[2]處在關閉輸入流時也拋出了IOException,那麼[3]處捕獲的異常到底是[1]處拋出的,仍是[2]處拋出的。事實上,若出現上述狀況,則[3]處實際捕獲到[2]處拋出的異常,會忽略[1]處拋出的異常。這是須要當心的地方!

以上是對異常,尤爲是Finally語句易錯點的總結,僅供參考。

相關文章
相關標籤/搜索