當前位置: 妍妍網 > 碼農

try catch finally的底層原理

2024-03-04碼農

來源:https://blog.csdn.net/lwd512768098/article/details/114728720

昨晚參加一個面試,被問到try catch finally相關的知識,雖然之前了解過其中奇怪的用法,特別有return的情況,但是由於時間久遠,完全忘了,導致這個問題回答不是很好,只是知道finally無論是否發生異常都會執行的(但是忘了含有return的情況是怎麽處理的了),finally常常用來關閉一些資源,像檔,連線等。

finally終究執行

我們先來驗證一下finally終究執行

publicstaticinttest() 
int i = 1;
try { 
i++;
finally { 
System.out.println("finally yeah!");
}
return i;
}
publicstaticvoidmain(String[] args
System.out.println(test());
}

輸出為

publicstaticinttest() 
int i = 1;
try { 
i++;
thrownew Exception();
catch (Exception e) { 
System.out.println("Exception yeah!");
finally { 
System.out.println("finally yeah!");
}
return i;
}
publicstaticvoidmain(String[] args
System.out.println(test());
}

從上面兩個例子中我們可以看到,無論是正確執行try塊還是在try塊發生了異常,finally塊都是被執行的

帶有return的情況

finally不帶return的情況

對於return情況的話,只要記住一句話就行,如果finally裏面有return, 那麽就會覆蓋try塊或者catch裏面的return內容,否則的話,在執行finally的內容之前(try塊或者catch裏面有return語句),會計算好try或者catch裏面的return運算式的值,然後保存到另一個局部變量,當執行fianlly的時候,會重新載入這個局部變量作為返回值,因此在finally的操作不會影響返回值,下面我們字節碼來看看內部的工作原理。

publicstaticinttest() 
int i = 1;
try { 
i++;
return i;
finally { 
i++;
System.out.println("finally yeah!");
}
}
publicstaticvoidmain(String[] args
System.out.println(test());
}

第一個問題:在try塊中含有return語句,你覺得finally語句還有執行麽?
第二個問題:最終結果是多少?

從上面可以看到,盡管try塊裏面有return, 但是finally塊仍然執行了,你肯定會好奇,那為啥返回值是2呢,finally裏面不是還進行了i++麽。

簡單分析一下,從結果看,finally仍然執行,說明try的return語句是還沒執行的,下面我們看看字節碼。

上面圖片已經標註很清楚了,如果還不明白的話,可以先去看一下這幾個字節碼命令,還是挺簡單的,註意的是,JVM操作都是基於運算元棧的。

總結一下,總體的意思就是,當執行完try塊的時候,會計算return運算式的值,然後把這個返回值存在另一個臨時變量裏面,最後返回的時候會重新讀取存放的變量,因此在finally後面無論如何修改,都不會影響返回值(除非finally裏面含有return,這個我們在下面討論)

finally帶有return

上面的情況是try或者catch裏面含有return,finally沒有return, 那麽fianlly裏面如何修改返回值是不會影響最後的返回值。下面討論finally裏面含有return的情況。

publicstaticinttest() 
int i = 1;
try { 
i++;
return i;
finally { 
i++;
System.out.println("finally yeah!");
return i;
}
}
publicstaticvoidmain(String[] args
System.out.println(test());
}

相信各位能夠正常猜出結果了

沒錯,返回了3,說明finally對i的修過是其效果的,我們從字節碼看看原因:

從上圖可以看到,在返回之前,載入的是0槽位的變量,這時0槽位的變量的值是3,1槽位的變量是2,所以返回的3。

由上可以得知,當finally中含有return的時候,會覆蓋之前try或者catch(上面沒有貼出實驗,需要驗證的可以去驗證,作者本人是驗證過了)裏面的返回值的

try, catch, finally均沒有return語句

這種情況比較簡單,跟finally含有return類似

publicstaticinttest() 
int i = 1;
try { 
i++;
finally { 
i++;
System.out.println("finally yeah!");
}
return i;
}
publicstaticvoidmain(String[] args
System.out.println(test());
}

總結

這裏總結一下, 只要finally裏面沒有return語句,那麽返回值就由try或者catch的return語句決定,否則由finally的return語句決定