Java.try catch finally 的執(zhí)行順序說明
示例1:
public static String hello() {
String s = "商務(wù)";
try {
return s;
} catch (Exception e) {
return "catch進來了";
} finally {
s = "你好世界";
return s;
}
}
返回結(jié)果:你好世界,此時的返回順序是 finally > try
示例2:
public static String hello() {
String s = "商務(wù)";
try {
return s;
} catch (Exception e) {
return "catch進來了";
} finally {
s = "你好世界";
}
}
返回結(jié)果:商務(wù)
因為在 try 處會進行 s 值的緩存
示例3:
public static void hehe() {
int a = 10;
try {
a += 1;
System.out.println(a);
throw new Exception("catch測試");
} 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 處拋出一個異常進入 catch,此時返回的順序是 try > catch > finally > 最后一行代碼
補充知識:Java異常獲取中try-catch-finally塊執(zhí)行順序
最近看面試題,發(fā)現(xiàn)這個比較好玩,try-catch-finally塊的執(zhí)行順序問題。
一般認為,finally最后執(zhí)行,做收尾工作,無論try塊是否捕獲異常,最后finally都會工作。但是這樣還是比較籠統(tǒng),如果沒有catch,而是將異常拋出,讓其他方法處理,那么是先進入其他方法還是先執(zhí)行finally?如果try塊中return了,那么finally還執(zhí)行不執(zhí)行?進一步,如果try、finally全部有return,那么執(zhí)行是怎樣的過程?
確實,異常這些還是最早學Java的時候?qū)W的,當時似乎也沒考慮這么多。借此機會研究一下異常獲取的順序。
節(jié)省時間,直接結(jié)論:
try->catch->finally按順序執(zhí)行,不管是否有異常,不管try中有什么操作,就算是return,也得往后稍稍,最后這個方法一定是要執(zhí)行finally。
如果try中拋出異常,而異常是留給上層方法處理,那么在拋出后,仍然運行finally,然后再回溯到上層。
自然,如果try中有return——也算是回溯了,返回值會存在棧中等待,等finally運行之后再回溯。
而如果finally中有return,那么直接從finally中結(jié)束方法。
如果在方法中直接結(jié)束程序,即調(diào)用System.exit()方法,那么就直接結(jié)束了,此時finally是不執(zhí)行的。由此可以認為,特殊情況導(dǎo)致程序的退出是可能導(dǎo)致一些問題的。畢竟finally一般寫的是關(guān)閉對象、資源的代碼。
通過代碼分析:
先寫了一個包含情況比較多的例子:
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是計數(shù)??梢钥吹?,整體上是先調(diào)用solve2方法,在其中調(diào)用solve1,solve1拋出了一個異常,讓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了一個異常,那么不會立刻回溯到上一個方法,而是仍然執(zhí)行finally。
通過solve1的執(zhí)行,我們可以認為,finally之前的所有代碼,正常執(zhí)行,但是返回之類的,全部被“卡”了下來,只有在finally執(zhí)行之后,才能繼續(xù)執(zhí)行。
這里就又有疑惑了,一般認為throw了一個異常,就算是回溯了,為什么finally仍然執(zhí)行了?如果這個不夠明顯,那么再看這個代碼:
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塊確實是運行了。再改一下代碼:
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確實是執(zhí)行的。
所以,認為finally是無論怎樣一定在方法的最后結(jié)束前執(zhí)行的。搜了一些資料,是說finally會在方法結(jié)束之前執(zhí)行,而之前所有的執(zhí)行,包括return,全部都停留在棧中,而finally最終執(zhí)行后才繼續(xù)。所以這樣也能解釋,第一次代碼本應(yīng)該回溯的代碼執(zhí)行完finally后才回溯,return的時候也是等finally執(zhí)行之后再執(zhí)行。
或許“return的時候也是等finally執(zhí)行之后再執(zhí)行”這句話又引出了一個問題:finally究竟是直接運行完結(jié)束,還是運行完之后再回到原來return的地方?
這里我們可以把i++換成++i,結(jié)果就不截圖了——finally就是最終執(zhí)行,如果有return,直接從finally返回。
還有一種情況,直接結(jié)束程序會怎么樣?
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
強制結(jié)束大過天。由此,也可以認為特殊情況導(dǎo)致程序直接結(jié)束,不會執(zhí)行finally。因為finally一般寫的都是關(guān)閉對象、資源的代碼,所以這些特殊情況導(dǎo)致的程序強制結(jié)束,可能會引發(fā)一些問題的。
以上這篇Java.try catch finally 的執(zhí)行順序說明就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
java LRU(Least Recently Used )詳解及實例代碼
這篇文章主要介紹了java LRU(Least Recently Used )詳解及實例代碼的相關(guān)資料,Java里面實現(xiàn)LRU緩存通常有兩種選擇,一種是使用LinkedHashMap,一種是自己設(shè)計數(shù)據(jù)結(jié)構(gòu),使用鏈表+HashMap,需要的朋友可以參考下2016-11-11
詳解Java中NullPointerException的處理方法
這篇文章將帶大家來單獨看一個很常見的異常--空指針異常,這個可以說是每個Java程序員都必知的異常,所以我們不得不單獨學習一下,文中有詳細的代碼示例,需要的朋友可以參考下2023-08-08
mybatis對象List<String> List<Integer>屬性映射方式
這篇文章主要介紹了mybatis對象List<String> List<Integer>屬性映射方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-12-12
Java?Runnable和Thread實現(xiàn)多線程哪個更好你知道嗎
這篇文章主要為大家詳細介紹了Java?Runnable和Thread實現(xiàn)多線程哪個更好,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助<BR>2022-03-03
在啟動后臺 jar包時,使用指定的 application.yml操作
這篇文章主要介紹了在啟動后臺 jar包時,使用指定的 application.yml操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-10-10

