java - try return
finally塊總是在Java中執行嗎? (20)
答案很簡單。
INPUT:
try{
int divideByZeroException = 5 / 0;
} catch (Exception e){
System.out.println("catch");
return; // also tried with break; in switch-case, got same output
} finally {
System.out.println("finally");
}
OUTPUT:
catch
finally
考慮到這段代碼,我可以絕對確定 finally
塊總是執行,無論是什麼something()
?
try {
something();
return success;
}
catch (Exception e) {
return failure;
}
finally {
System.out.println("i don't know if this will get printed out.");
}
不,並不總是一個例外情況是// System.exit(0); 在finally塊阻止最終執行之前。
class A {
public static void main(String args[]){
DataInputStream cin = new DataInputStream(System.in);
try{
int i=Integer.parseInt(cin.readLine());
}catch(ArithmeticException e){
}catch(Exception e){
System.exit(0);//Program terminates before executing finally block
}finally{
System.out.println("Won't be executed");
System.out.println("No error");
}
}
}
因為無論你有什麼案例,總是會被調用。 你沒有異常,它仍然被調用,捕獲異常,它仍然被調用
因為除非你調用System.exit()
(或線程崩潰),否則將始終調用finally塊。
如果拋出異常,最後運行。 如果沒有拋出異常,最後運行。 如果捕獲到異常,則最終運行。 如果未捕獲異常,則最終運行。
只有當JVM退出時它才會運行。
我嘗試了上面的例子,略有修改 -
public static void main(final String[] args) {
System.out.println(test());
}
public static int test() {
int i = 0;
try {
i = 2;
return i;
} finally {
i = 12;
System.out.println("finally trumps return.");
}
}
上面的代碼輸出:
最後勝過回歸。
2
這是因為當return i;
執行後, i
有一個值2.此後執行finally
塊,其中12被分配給i
,然後執行System.out
out。
執行finally
塊後, try
塊返回2,而不是返回12,因為這個return語句不會再次執行。
如果您將在Eclipse中調試此代碼,那麼您會感覺在執行finally
塊的System.out
,再次執行try
塊的return
語句。 但這種情況並非如此。 它只返回值2。
是的,它會的。 只有JVM退出或崩潰才會出現這種情況
是的,它會的。 無論你的try或catch塊發生了什麼,除非調用System.exit()或JVM崩潰。 如果塊中有任何return語句,則最終將在該return語句之前執行。
是的,最後塊總是執行。 大多數開發人員使用此塊關閉數據庫連接,結果集對象,語句對像以及使用java hibernate來回滾事務。
最後塊總是執行是否處理異常。如果在try塊之前發生任何異常,則finally塊將不會執行。
最後總是運行這是整點,只是因為它在返回後出現在代碼中並不意味著它是如何實現的。 退出try
塊時,Java運行時負責運行此代碼。
例如,如果您有以下內容:
int foo() {
try {
return 42;
}
finally {
System.out.println("done");
}
}
運行時將生成如下內容:
int foo() {
int ret = 42;
System.out.println("done");
return 42;
}
如果拋出未捕獲的異常,則finally
塊將運行,異常將繼續傳播。
此外,雖然這是不好的做法,如果在finally塊中有一個return語句,它將勝過常規塊中的任何其他返回。 也就是說,以下塊將返回false:
try { return true; } finally { return false; }
從finally塊中拋出異常也是一樣的。
簡而言之,在官方Java文檔(點擊here )中,寫道 -
如果在執行try或catch代碼時JVM退出,則finally塊可能無法執行。 同樣,如果執行try或catch代碼的線程被中斷或終止,則即使應用程序作為一個整體繼續,finally塊也可能不會執行。
考慮以下程序:
public class someTest {
private static StringBuilder sb = new StringBuilder();
public static void main(String args[]) {
System.out.println(someString());
System.out.println("---AGAIN---");
System.out.println(someString());
}
private static String someString() {
try {
sb.append("-abc-");
return sb.toString();
} finally {
sb.append("xyz");
}
}
}
從Java 1.8.162開始,上面的代碼塊給出了以下輸出:
-abc-
---AGAIN---
-abc-xyz-abc-
這意味著finally
使用釋放對像是一個很好的做法,如下面的代碼:
private static String someString() {
StringBuilder sb = new StringBuilder();
try {
sb.append("abc");
return sb.toString();
} finally {
sb = null;
}
}
試試這段代碼,你會理解finally塊中的代碼是在return語句之後執行的 。
public class TestTryCatchFinally {
static int x = 0;
public static void main(String[] args){
System.out.println(f1() );
System.out.println(f2() );
}
public static int f1(){
try{
x = 1;
return x;
}finally{
x = 2;
}
}
public static int f2(){
return x;
}
}
這在任何語言中都是正確的...最終將始終在return語句之前執行,無論方法體中返回的位置如何。 如果不是這樣的話,那麼finally塊就沒有多大意義了。
這是Java語言規範中的官方文字。
14.20.2。 執行try-finally和try-catch-finally
通過首先執行
try
塊來執行具有finally
塊的try
語句。 然後有一個選擇:
- 如果
try
塊的執行正常完成,[...]- 如果由於
throw
值V而突然完成try
塊的執行,[...]- 如果
try
塊的執行由於任何其他原因R突然完成,則執行finally
塊。 然後有一個選擇:
- 如果finally塊正常完成,那麼
try
語句突然完成,原因是R。- 如果
finally
塊因為原因S而突然完成,則try
語句突然完成,原因是S ( 並且原因R被丟棄 )。
return
的規範實際上使這個明確:
ReturnStatement: return Expression(opt) ;
沒有
Expression
return
語句嘗試將控制權轉移給包含它的方法或構造函數的調用者。帶有
Expression
return
語句嘗試將控制權轉移給包含它的方法的調用者;Expression
的值成為方法調用的值。前面的描述說“ 嘗試轉移控制 ”而不僅僅是“ 轉移控制 ”,因為如果在
try
塊中包含return
語句的方法或構造函數中有任何try
語句,那麼將執行那些try
語句的任何finally
子句,在將控制權轉移給方法或構造函數的調用者之前,從最裡面到最外面的順序。 突然完成finally
子句可以破壞由return
語句啟動的控制轉移。
這是因為您將i的值指定為12,但未將i的值返回給函數。 正確的代碼如下:
public static int test() {
int i = 0;
try {
return i;
} finally {
i = 12;
System.out.println("finally trumps return.");
return i;
}
}
除了最後替換try塊中的返回的返回點之外,異常也是如此。 拋出異常的finally塊將替換try塊內拋出的返回或異常。
除非由於JVM崩潰或調用System.exit(0)
導致程序異常終止,否則始終執行finally塊。
最重要的是,finally塊中返回的任何值都將覆蓋執行finally塊之前返回的值,因此在使用try finally時要小心檢查所有出口點。