找工做時,有這樣一道題: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語句易錯點的總結,僅供參考。