Java.try catch finally 的執(zhí)行順序說明
示例1:
public static String hello() { String s = "商務(wù)"; try { return s; } catch (Exception e) { return "catch進(jìn)來了"; } finally { s = "你好世界"; return s; } }
返回結(jié)果:你好世界,此時(shí)的返回順序是 finally > try
示例2:
public static String hello() { String s = "商務(wù)"; try { return s; } catch (Exception e) { return "catch進(jìn)來了"; } finally { s = "你好世界"; } }
返回結(jié)果:商務(wù)
因?yàn)樵?try 處會(huì)進(jìn)行 s 值的緩存
示例3:
public static void hehe() { int a = 10; try { a += 1; System.out.println(a); throw new Exception("catch測(cè)試"); } catch (Exception e) { e.printStackTrace(); a += 10; System.out.println(a); } finally { a += 10000; System.out.println(a); } System.out.println(a); }
返回結(jié)果:
11
21
10021
10021
故意在 try 處拋出一個(gè)異常進(jìn)入 catch,此時(shí)返回的順序是 try > catch > finally > 最后一行代碼
補(bǔ)充知識(shí):Java異常獲取中try-catch-finally塊執(zhí)行順序
最近看面試題,發(fā)現(xiàn)這個(gè)比較好玩,try-catch-finally塊的執(zhí)行順序問題。
一般認(rèn)為,finally最后執(zhí)行,做收尾工作,無論try塊是否捕獲異常,最后finally都會(huì)工作。但是這樣還是比較籠統(tǒng),如果沒有catch,而是將異常拋出,讓其他方法處理,那么是先進(jìn)入其他方法還是先執(zhí)行finally?如果try塊中return了,那么finally還執(zhí)行不執(zhí)行?進(jìn)一步,如果try、finally全部有return,那么執(zhí)行是怎樣的過程?
確實(shí),異常這些還是最早學(xué)Java的時(shí)候?qū)W的,當(dāng)時(shí)似乎也沒考慮這么多。借此機(jī)會(huì)研究一下異常獲取的順序。
節(jié)省時(shí)間,直接結(jié)論:
try->catch->finally按順序執(zhí)行,不管是否有異常,不管try中有什么操作,就算是return,也得往后稍稍,最后這個(gè)方法一定是要執(zhí)行finally。
如果try中拋出異常,而異常是留給上層方法處理,那么在拋出后,仍然運(yùn)行finally,然后再回溯到上層。
自然,如果try中有return——也算是回溯了,返回值會(huì)存在棧中等待,等finally運(yùn)行之后再回溯。
而如果finally中有return,那么直接從finally中結(jié)束方法。
如果在方法中直接結(jié)束程序,即調(diào)用System.exit()方法,那么就直接結(jié)束了,此時(shí)finally是不執(zhí)行的。由此可以認(rèn)為,特殊情況導(dǎo)致程序的退出是可能導(dǎo)致一些問題的。畢竟finally一般寫的是關(guān)閉對(duì)象、資源的代碼。
通過代碼分析:
先寫了一個(gè)包含情況比較多的例子:
package me.iwts; public class Main{ public static int rank; public static void solve1() throws Exception{ try { System.out.println("solve 1 try,rank: "+rank++); throw new Exception("throw by solve 1"); }finally { System.out.println("solve 1 finally,rank: "+rank++); } } public static void solve2(){ try{ System.out.println("solve 2 try,rank: "+rank++); solve1(); }catch (Exception ex){ System.out.println("catch exception : "+ex.getMessage()+",rank: "+rank++); }finally { System.out.println("solve 1 finally,rank: "+rank++); } } public static void main(String args[]) { rank = 1; solve2(); System.out.println("over"); } }
rank是計(jì)數(shù)??梢钥吹?,整體上是先調(diào)用solve2方法,在其中調(diào)用solve1,solve1拋出了一個(gè)異常,讓solve2捕獲處理。大家可以先自己猜一下。
下面是返回答案:
solve 2 try,rank: 1
solve 1 try,rank: 2
solve 1 finally,rank: 3
catch exception : throw by solve 1,rank: 4
solve 1 finally,rank: 5
over
根據(jù)上面的結(jié)果可以分析:try-catch-finally執(zhí)行順序:首先是try執(zhí)行,如果發(fā)生異常,那么直接捕獲異常,最后執(zhí)行finally。但是,如果拋出異常,例如在solve1方法中,throw了一個(gè)異常,那么不會(huì)立刻回溯到上一個(gè)方法,而是仍然執(zhí)行finally。
通過solve1的執(zhí)行,我們可以認(rèn)為,finally之前的所有代碼,正常執(zhí)行,但是返回之類的,全部被“卡”了下來,只有在finally執(zhí)行之后,才能繼續(xù)執(zhí)行。
這里就又有疑惑了,一般認(rèn)為throw了一個(gè)異常,就算是回溯了,為什么finally仍然執(zhí)行了?如果這個(gè)不夠明顯,那么再看這個(gè)代碼:
package me.iwts; public class Main{ public static int solve(){ try{ System.out.println("try"); return 1; }finally { System.out.println("finally"); return 2; } } public static void main(String args[]) { System.out.println(solve()); } }
返回值是多少?
try
finally
2
try塊都已經(jīng)return了,最后為什么是返回的return2?并且try塊確實(shí)是運(yùn)行了。再改一下代碼:
package me.iwts; public class Main{ public static int solve(){ int i = 1; try{ System.out.println("try"); return i++; }finally { System.out.println("finally"); return i; } } public static void main(String args[]) { System.out.println(solve()); } }
注意,try塊返回了i++,那么我們debug就能看出來return這句到底是執(zhí)行還是沒執(zhí)行,那么有這樣的圖:
可以看到,return確實(shí)是執(zhí)行的。
所以,認(rèn)為finally是無論怎樣一定在方法的最后結(jié)束前執(zhí)行的。搜了一些資料,是說finally會(huì)在方法結(jié)束之前執(zhí)行,而之前所有的執(zhí)行,包括return,全部都停留在棧中,而finally最終執(zhí)行后才繼續(xù)。所以這樣也能解釋,第一次代碼本應(yīng)該回溯的代碼執(zhí)行完finally后才回溯,return的時(shí)候也是等finally執(zhí)行之后再執(zhí)行。
或許“return的時(shí)候也是等finally執(zhí)行之后再執(zhí)行”這句話又引出了一個(gè)問題:finally究竟是直接運(yùn)行完結(jié)束,還是運(yùn)行完之后再回到原來return的地方?
這里我們可以把i++換成++i,結(jié)果就不截圖了——finally就是最終執(zhí)行,如果有return,直接從finally返回。
還有一種情況,直接結(jié)束程序會(huì)怎么樣?
package me.iwts; public class Main{ public static void solve(){ try{ System.out.println("try"); System.exit(0); }finally { System.out.println("finally"); } } public static void main(String args[]) { solve(); } }
結(jié)果:
try
強(qiáng)制結(jié)束大過天。由此,也可以認(rèn)為特殊情況導(dǎo)致程序直接結(jié)束,不會(huì)執(zhí)行finally。因?yàn)閒inally一般寫的都是關(guān)閉對(duì)象、資源的代碼,所以這些特殊情況導(dǎo)致的程序強(qiáng)制結(jié)束,可能會(huì)引發(fā)一些問題的。
以上這篇Java.try catch finally 的執(zhí)行順序說明就是小編分享給大家的全部內(nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
spring boot Rabbit高級(jí)教程(最新推薦)
RabbitMQ的消息過期是基于追溯方式來實(shí)現(xiàn)的,也就是說當(dāng)一個(gè)消息的TTL到期以后不一定會(huì)被移除或投遞到死信交換機(jī),而是在消息恰好處于隊(duì)首時(shí)才會(huì)被處理,本篇文章給大家介紹spring boot Rabbit高級(jí)教程,感興趣的朋友一起看看吧2023-10-10利用Java中Calendar計(jì)算兩個(gè)日期之間的天數(shù)和周數(shù)
Java 語言的Calendar(日歷),Date(日期),和DateFormat(日期格式)組成了Java標(biāo)準(zhǔn)的一個(gè)基本但是非常重要的部分。日期是商業(yè)邏輯計(jì)算一個(gè)關(guān)鍵的部分。下面這篇文章就給大家介紹了如何利用Java中Calendar計(jì)算兩個(gè)日期之間的天數(shù)和周數(shù),下面來一起看看吧。2016-12-12Java怎么獲取當(dāng)前時(shí)間、計(jì)算程序運(yùn)行時(shí)間源碼詳解(超詳細(xì)!)
有的時(shí)候,我們需要查看某一段代碼的性能如何,最為簡(jiǎn)單的方式,可以通過計(jì)算該段代碼執(zhí)行的耗時(shí),來進(jìn)行簡(jiǎn)單的判斷,這篇文章主要給大家介紹了關(guān)于Java怎么獲取當(dāng)前時(shí)間、計(jì)算程序運(yùn)行時(shí)間的相關(guān)資料,需要的朋友可以參考下2024-07-07springboot中縮短一個(gè)url鏈接的實(shí)現(xiàn)
縮短 URL 是現(xiàn)代應(yīng)用程序中常見的需求,通常用于減少長 URL 的長度,使其更易于分享,URL 縮短服務(wù)的核心思路是將長 URL 映射到一個(gè)唯一的短代碼,本文主要介紹了springboot中縮短一個(gè)url鏈接的實(shí)現(xiàn),感興趣的可以了解一下2024-09-09關(guān)于IDEA無法預(yù)覽Markdown文件的解決思路
在IntelliJ IDEA中,有時(shí)Markdown文件無法預(yù)覽可能是因?yàn)槲募P(guān)聯(lián)設(shè)置不正確或配置信息錯(cuò)誤,首先,檢查IDE的File Types設(shè)置,確保.md和.markdown后綴已正確注冊(cè),其次,對(duì)照官方配置信息,調(diào)整Markdown設(shè)置2024-09-09集成apollo動(dòng)態(tài)日志取締logback-spring.xml配置
這篇文章主要為大家介紹了集成apollo動(dòng)態(tài)日志取締logback-spring.xml配置的過程內(nèi)容詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助2022-02-02