摘要:在語言規范中也提到如果在語句塊中包含語句,那么語句會在其之前執行。并且還需要注意的是,中的會覆蓋中的。
關于 try 和 finally 中的 return
首先我們來看一段代碼:
public class Test { public static int inc() { int x = 1; try { return ++x; // 1* } catch (Exception e) { } finally { x++; } return x; } public static void main(String[] args) { System.out.println(inc()); } }
它的輸出結果是多少呢?
2
我們走一下這個過程,x 的初始值是 1,然后進入到了 try 語句塊中,在 1* 處,++x,x 會先自增,現在 x = 2,之后 return,return 是用來跳出當前方法,而 finally 是無論 try 語句發生了什么,都會執行的一個語句塊,那么 try 中 return 和 finally 執行的順序到底是誰先誰后呢?
我們來看 Oracle 文檔中對 finally Block 的描述 The finally Block (The Java? Tutorials > Essential Classes > Exceptions)
The finally BlockThe finally block always executes when the try block exits. This ensures that the finally block is executed even if an unexpected exception occurs. But finally is useful for more than just exception handling — it allows the programmer to avoid having cleanup code accidentally bypassed by a return, continue, or break. Putting cleanup code in a finally block is always a good practice, even when no exceptions are anticipated.
Note: If the JVM exits while the try or catch code is being executed, then the finally block may not execute. Likewise, if the thread executing the try or catch code is interrupted or killed, the finally block may not execute even though the application as a whole continues.
從這段解釋中我們可以知道,當 try 語句塊退出時,finally 語句塊總是會執行,這保證了當有異常發生時,finally 語句塊會被執行,不過 finally 語句塊的作用不僅于此,它幫助程序員避免在執行 return or continue or break 時繞過清理代碼,所以即使沒有異常需要捕獲,將清理代碼放到 finally 語句塊中也是一個好的選擇。
需要注意的是,只有一種情況:如果在執行 try or catch 語句時 JVM 退出了,比如我們調用 System.exit,那么 finally 才不會被執行。
在 Java 語言規范 Chapter?14.?Blocks and Statements 中也提到:
The preceding descriptions say "attempts to transfer control" rather than just "transfers control" because if there are any try statements (§14.20) within the method or constructor whose try blocks or catch clauses contain the return statement, then any finally clauses of those try statements will be executed, in order, innermost to outermost, before control is transferred to the invoker of the method or constructor. Abrupt completion of a finally clause can disrupt the transfer of control initiated by a return statement.
如果在 try or catch 語句塊中包含 return 語句,那么 finally 語句會在其 return 之前執行。
根據以上描述,我們知道了 finally 語句塊會在 try or catch 語句塊執行前執行,那么當 x 自增后,會繼續執行 finally 語句塊中的內容,即 x++,那么此時 x = 3,可是這段程序的返回結果是 2 ,這又是為什么呢?
我們來看 JVM 規范中的描述 Chapter?4.?The class File Format
Control can be transferred to the finally clause (the finally subroutine can be invoked) in several different ways. If the try clause completes normally, the finally subroutine is invoked via a jsr instruction before evaluating the next expression. A break or continue inside the try clause that transfers control outside the try clause executes a jsr to the code for the finally clause first. If the try clause executes a return, the compiled code does the following:
Saves the return value (if any) in a local variable.
Executes a jsr to the code for the finally clause.
Upon return from the finally clause, returns the value saved in the local variable.
也就是說,如果 try 語句中包含 return,那么編譯后的代碼會執行以下操作:
將 return 的值存到一個局部變量中
執行 jsr 指令到 finally 語句塊中的代碼
從 finally 語句返回時,返回在局部變量中保存的值
終于,謎團揭開了!原來在 finally 語句中執行完畢后,它會返回存在局部變量中的在 try 語句塊中 return 的值,因此它返回的是 1* 處的 x,也就是返回的 2。
并且還需要注意的是,finally 中的 return 會覆蓋 try 中的 return。
參考資料:
http://www.cnblogs.com/averey...
https://docs.oracle.com/javase
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/69373.html
摘要:隨著的出現,我最近發現自己在我的代碼中使用了更多。但老實說,我終于用做了一點練習。當我去實際使用它時,我有點不確定它的細節。事實上,這就是本文的靈感來源。 隨著async /await的出現,我最近發現自己在我的代碼中使用了更多try /catch /finally。但老實說,我終于用finally做了一點練習。當我去實際使用它時,我有點不確定它的細節。所以我把幾個例子放在一起。 當你...
摘要:隨著的出現,我最近發現自己在我的代碼中使用了更多。但老實說,我終于用做了一點練習。當我去實際使用它時,我有點不確定它的細節。事實上,這就是本文的靈感來源。 隨著async /await的出現,我最近發現自己在我的代碼中使用了更多try /catch /finally。但老實說,我終于用finally做了一點練習。當我去實際使用它時,我有點不確定它的細節。所以我把幾個例子放在一起。 當你...
摘要:隨著的出現,我最近發現自己在我的代碼中使用了更多。但老實說,我終于用做了一點練習。當我去實際使用它時,我有點不確定它的細節。事實上,這就是本文的靈感來源。 隨著async /await的出現,我最近發現自己在我的代碼中使用了更多try /catch /finally。但老實說,我終于用finally做了一點練習。當我去實際使用它時,我有點不確定它的細節。所以我把幾個例子放在一起。 當你...
摘要:基礎系列的與方法類初始化順序線程池如何彈性伸縮的幾個要點的緩存什么場景下使用阻塞隊列的使用及模式中的序本文主要簡述中有的情況。參考關于中的執行順序 Java基礎系列 Java的hashcode與equals方法 Java類初始化順序 ThreadPoolExecutor線程池如何彈性伸縮 HashMap的幾個要點 Integer的緩存 什么場景下使用阻塞隊列 volatile的使用及...
閱讀 1289·2023-04-25 19:33
閱讀 1171·2021-10-21 09:39
閱讀 3644·2021-09-09 09:32
閱讀 2614·2019-08-30 10:58
閱讀 1600·2019-08-29 16:17
閱讀 873·2019-08-29 15:29
閱讀 2885·2019-08-26 11:55
閱讀 2658·2019-08-26 10:33