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塊的執行正常完成,[...]
  • 如果由於throwV而突然完成try塊的執行,[...]
  • 如果try塊的執行由於任何其他原因R突然完成,則執行finally塊。 然後有一個選擇:
    • 如果finally塊正常完成,那麼try語句突然完成,原因是R。
    • 如果finally塊因為原因S而突然完成,則try語句突然完成,原因是S並且原因R被丟棄 )。

return的規範實際上使這個明確:

JLS 14.17返迴聲明

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時要小心檢查所有出口點。





try-catch-finally