摘要:在語(yǔ)言規(guī)范中也提到如果在語(yǔ)句塊中包含語(yǔ)句,那么語(yǔ)句會(huì)在其之前執(zhí)行。并且還需要注意的是,中的會(huì)覆蓋中的。
關(guān)于 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()); } }
它的輸出結(jié)果是多少呢?
2
我們走一下這個(gè)過程,x 的初始值是 1,然后進(jìn)入到了 try 語(yǔ)句塊中,在 1* 處,++x,x 會(huì)先自增,現(xiàn)在 x = 2,之后 return,return 是用來跳出當(dāng)前方法,而 finally 是無論 try 語(yǔ)句發(fā)生了什么,都會(huì)執(zhí)行的一個(gè)語(yǔ)句塊,那么 try 中 return 和 finally 執(zhí)行的順序到底是誰(shuí)先誰(shuí)后呢?
我們來看 Oracle 文檔中對(duì) 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.
從這段解釋中我們可以知道,當(dāng) try 語(yǔ)句塊退出時(shí),finally 語(yǔ)句塊總是會(huì)執(zhí)行,這保證了當(dāng)有異常發(fā)生時(shí),finally 語(yǔ)句塊會(huì)被執(zhí)行,不過 finally 語(yǔ)句塊的作用不僅于此,它幫助程序員避免在執(zhí)行 return or continue or break 時(shí)繞過清理代碼,所以即使沒有異常需要捕獲,將清理代碼放到 finally 語(yǔ)句塊中也是一個(gè)好的選擇。
需要注意的是,只有一種情況:如果在執(zhí)行 try or catch 語(yǔ)句時(shí) JVM 退出了,比如我們調(diào)用 System.exit,那么 finally 才不會(huì)被執(zhí)行。
在 Java 語(yǔ)言規(guī)范 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 語(yǔ)句塊中包含 return 語(yǔ)句,那么 finally 語(yǔ)句會(huì)在其 return 之前執(zhí)行。
根據(jù)以上描述,我們知道了 finally 語(yǔ)句塊會(huì)在 try or catch 語(yǔ)句塊執(zhí)行前執(zhí)行,那么當(dāng) x 自增后,會(huì)繼續(xù)執(zhí)行 finally 語(yǔ)句塊中的內(nèi)容,即 x++,那么此時(shí) x = 3,可是這段程序的返回結(jié)果是 2 ,這又是為什么呢?
我們來看 JVM 規(guī)范中的描述 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 語(yǔ)句中包含 return,那么編譯后的代碼會(huì)執(zhí)行以下操作:
將 return 的值存到一個(gè)局部變量中
執(zhí)行 jsr 指令到 finally 語(yǔ)句塊中的代碼
從 finally 語(yǔ)句返回時(shí),返回在局部變量中保存的值
終于,謎團(tuán)揭開了!原來在 finally 語(yǔ)句中執(zhí)行完畢后,它會(huì)返回存在局部變量中的在 try 語(yǔ)句塊中 return 的值,因此它返回的是 1* 處的 x,也就是返回的 2。
并且還需要注意的是,finally 中的 return 會(huì)覆蓋 try 中的 return。
參考資料:
http://www.cnblogs.com/averey...
https://docs.oracle.com/javase
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/69373.html
摘要:隨著的出現(xiàn),我最近發(fā)現(xiàn)自己在我的代碼中使用了更多。但老實(shí)說,我終于用做了一點(diǎn)練習(xí)。當(dāng)我去實(shí)際使用它時(shí),我有點(diǎn)不確定它的細(xì)節(jié)。事實(shí)上,這就是本文的靈感來源。 隨著async /await的出現(xiàn),我最近發(fā)現(xiàn)自己在我的代碼中使用了更多try /catch /finally。但老實(shí)說,我終于用finally做了一點(diǎn)練習(xí)。當(dāng)我去實(shí)際使用它時(shí),我有點(diǎn)不確定它的細(xì)節(jié)。所以我把幾個(gè)例子放在一起。 當(dāng)你...
摘要:隨著的出現(xiàn),我最近發(fā)現(xiàn)自己在我的代碼中使用了更多。但老實(shí)說,我終于用做了一點(diǎn)練習(xí)。當(dāng)我去實(shí)際使用它時(shí),我有點(diǎn)不確定它的細(xì)節(jié)。事實(shí)上,這就是本文的靈感來源。 隨著async /await的出現(xiàn),我最近發(fā)現(xiàn)自己在我的代碼中使用了更多try /catch /finally。但老實(shí)說,我終于用finally做了一點(diǎn)練習(xí)。當(dāng)我去實(shí)際使用它時(shí),我有點(diǎn)不確定它的細(xì)節(jié)。所以我把幾個(gè)例子放在一起。 當(dāng)你...
摘要:隨著的出現(xiàn),我最近發(fā)現(xiàn)自己在我的代碼中使用了更多。但老實(shí)說,我終于用做了一點(diǎn)練習(xí)。當(dāng)我去實(shí)際使用它時(shí),我有點(diǎn)不確定它的細(xì)節(jié)。事實(shí)上,這就是本文的靈感來源。 隨著async /await的出現(xiàn),我最近發(fā)現(xiàn)自己在我的代碼中使用了更多try /catch /finally。但老實(shí)說,我終于用finally做了一點(diǎn)練習(xí)。當(dāng)我去實(shí)際使用它時(shí),我有點(diǎn)不確定它的細(xì)節(jié)。所以我把幾個(gè)例子放在一起。 當(dāng)你...
摘要:基礎(chǔ)系列的與方法類初始化順序線程池如何彈性伸縮的幾個(gè)要點(diǎn)的緩存什么場(chǎng)景下使用阻塞隊(duì)列的使用及模式中的序本文主要簡(jiǎn)述中有的情況。參考關(guān)于中的執(zhí)行順序 Java基礎(chǔ)系列 Java的hashcode與equals方法 Java類初始化順序 ThreadPoolExecutor線程池如何彈性伸縮 HashMap的幾個(gè)要點(diǎn) Integer的緩存 什么場(chǎng)景下使用阻塞隊(duì)列 volatile的使用及...
閱讀 1300·2023-04-25 19:33
閱讀 1184·2021-10-21 09:39
閱讀 3656·2021-09-09 09:32
閱讀 2634·2019-08-30 10:58
閱讀 1638·2019-08-29 16:17
閱讀 889·2019-08-29 15:29
閱讀 2902·2019-08-26 11:55
閱讀 2670·2019-08-26 10:33