2584

このコードを考えると、何が何であれ、ブロックが常に実行されることを絶対に確信できますか?finallysomething()

try {  
    something();  
    return success;  
}  
catch (Exception e) {   
    return failure;  
}  
finally {  
    System.out.println("I don't know if this will get printed out");
}
4

51 に答える 51

2910

はい、またはコード ブロックfinallyの実行後に呼び出されます。trycatch

finally呼び出されないのは次の場合のみです。

  1. 呼び出す場合System.exit()
  2. 呼び出す場合Runtime.getRuntime().halt(exitStatus)
  3. JVM が最初にクラッシュした場合
  4. tryJVM がorcatchブロック内で無限ループ (またはその他の割り込み不可で終了しないステートメント) に達した場合
  5. OS が JVM プロセスを強制終了した場合。たとえば、kill -9 <pid>UNIXの場合
  6. ホスト システムが停止した場合。例: 電源障害、ハードウェア エラー、OS パニックなど
  7. finallyブロックがデーモン スレッドによって実行され、他のすべての非デーモン スレッドfinallyが呼び出される前に終了する場合
于 2008-09-15T17:45:39.203 に答える
606

コード例:

public static void main(String[] args) {
    System.out.println(Test.test());
}

public static int test() {
    try {
        return 0;
    }
    finally {
        System.out.println("something is printed");
    }
}

出力:

something is printed. 
0
于 2008-09-15T17:59:52.460 に答える
413

また、これは悪い習慣ですが、finally ブロック内に return ステートメントがある場合、通常のブロックからの他のすべての return よりも優先されます。つまり、次のブロックは false を返します。

try { return true; } finally { return false; }

finally ブロックから例外をスローする場合も同じです。

于 2008-09-15T18:19:53.507 に答える
262

Java 言語仕様の公式用語は次のとおりです。

14.20.2. try-finally と try-catch-finally の実行

ブロックを含むtryステートメントは、finally最初にブロックを実行することによって実行されtryます。次に、選択肢があります。

  • ブロックの実行がtry正常に完了すると、 [...]
  • Vが原因でブロックの実行がtry突然終了した場合[...]throw
  • ブロックの実行がRtry以外の理由で突然終了した場合、そのブロックは実行されます。次に、選択肢があります。finally
    • finally ブロックが正常に完了すると、ステートメントはRtryの理由で突然完了します。
    • finallyブロックが理由Sで突然終了した場合、tryステートメントは理由 S で突然終了します(理由Rは破棄されます)。

の仕様では、return実際にはこれが明示されています。

JLS 14.17 return ステートメント

ReturnStatement:
     return Expression(opt) ;

それを含むメソッドまたはコンストラクターの呼び出し元に制御を移そreturnとしないステートメント。Expression

それを含むメソッドの呼び出し元に制御を移そうとするreturnステートメントを含むステートメント。の値がメソッド呼び出しの値になります。Expression Expression

前述の説明では、単に「制御を転送する」ではなく、「制御を転送しようとする」と述べますこれは、ブロックにステートメントが含まれるメソッドまたはコンストラクター内にステートメントがある場合、それらのステートメントのすべての句が最も内側から最も外側の順序で実行されるためです。 、制御がメソッドまたはコンストラクターの呼び出し元に転送される前。句が突然完了すると、ステートメントによって開始された制御の転送が中断される可能性があります。trytryreturnfinallytryfinallyreturn

于 2010-05-25T06:50:16.820 に答える
171

他の応答に加えて、'finally' には、try..catch ブロックによって例外/戻り値をオーバーライドする権利があることを指摘することが重要です。たとえば、次のコードは 12 を返します。

public static int getMonthsInYear() {
    try {
        return 10;
    }
    finally {
        return 12;
    }
}

同様に、次のメソッドは例外をスローしません。

public static int getMonthsInYear() {
    try {
        throw new RuntimeException();
    }
    finally {
        return 12;
    }
}

次のメソッドはそれをスローしますが:

public static int getMonthsInYear() {
    try {
        return 12;          
    }
    finally {
        throw new RuntimeException();
    }
}
于 2010-05-13T07:11:59.567 に答える
127

上記の例を少し変更して試しました-

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

これは、when return i;is executableiの値が 2 であるためです。この後finally、12 が割り当てられたブロックが実行されi、次にSystem.outout が実行されます。

finallyブロックを実行した後、ブロックtryは 12 ではなく 2 を返します。これは、この return ステートメントが再度実行されないためです。

このコードを Eclipse でデバッグすると、ブロックの実行後System.outfinallyブロックのreturnステートメントがtry再度実行されるように感じるでしょう。しかし、そうではありません。単純に値 2 を返します。

于 2008-11-17T16:25:36.027 に答える
126

これがケビンの答えの詳細です。finally後で返される場合でも、返される式は の前に評価されることを知っておくことが重要です。

public static void main(String[] args) {
    System.out.println(Test.test());
}

public static int printX() {
    System.out.println("X");
    return 0;
}

public static int test() {
    try {
        return printX();
    }
    finally {
        System.out.println("finally trumps return... sort of");
    }
}

出力:

X
finally trumps return... sort of
0
于 2013-12-03T23:36:13.040 に答える
52

それがfinallyブロックの全体像です。もちろん、特に戻ってきたためにスキップされる可能性のあるクリーンアップを確実に実行できます。

最後に、tryブロックで何が起こったかに関係なく呼び出されます(呼び出すか、Java仮想マシンが他の理由で起動しない限り)。System.exit(int)

于 2010-05-13T06:19:17.580 に答える
42

これについて考える論理的な方法は次のとおりです。

  1. finally ブロックに配置されたコードは、try ブロック内で何が発生しても実行する必要があります
  2. したがって、try ブロック内のコードが値を返そうとしたり、例外をスローしようとしたりすると、finally ブロックが実行できるようになるまで、アイテムは「棚に」置かれます。
  3. finally ブロック内のコードは (定義により) 優先度が高いため、好きなものを返したりスローしたりできます。その場合、「棚に」残っているものはすべて破棄されます。
  4. これに対する唯一の例外は、'System.exit' などによって、try ブロック中に VM が完全にシャットダウンした場合です。
于 2008-09-15T19:26:44.797 に答える
21

finally は、プログラムの異常終了 (System.exit(0) の呼び出しなど) がない限り、常に実行されます。したがって、sysoutが出力されます

于 2008-09-15T17:46:18.343 に答える
18

JVMのクラッシュまたはへの呼び出しのいずれかが原因でプログラムが異常終了しない限り、finallyブロックは常に実行されSystem.exit(0)ます。

さらに、finallyブロック内から返された値は、finallyブロックの実行前に返された値を上書きするため、tryfinallyを使用するときはすべての出口点をチェックするように注意してください。

于 2008-09-15T18:11:55.660 に答える
18

また、最後に戻ると、すべての例外が破棄されます。 http://jamesjava.blogspot.com/2006/03/dont-return-in-finally-clause.html

于 2008-09-15T19:26:15.717 に答える
12

最後に、常に実行されます。これは、戻り値の後にコードに表示されるからといって、それが実装されていることを意味するわけではありません。Javaランタイムには、tryブロックを終了するときにこのコードを実行する責任があります。

たとえば、次の場合:

int foo() { 
    try {
        return 42;
    }
    finally {
        System.out.println("done");
    }
}

ランタイムは次のようなものを生成します:

int foo() {
    int ret = 42;
    System.out.println("done");
    return 42;
}

キャッチされない例外がスローされると、finallyブロックが実行され、例外が伝播し続けます。

于 2010-05-13T06:18:23.697 に答える
10

呼び出すSystem.exit()(またはスレッドがクラッシュする)場合を除いて、finallyブロックが常に呼び出されるためです。

于 2010-05-13T06:19:17.147 に答える
10

これは、i の値を 12 として代入したが、i の値を関数に返さなかったためです。正しいコードは次のとおりです。

public static int test() {
    int i = 0;
    try {
        return i;
    } finally {
        i = 12;
        System.out.println("finally trumps return.");
        return i;
    }
}
于 2010-05-25T06:36:29.320 に答える
10

簡潔に言えば、公式のJavaドキュメント(ここをクリックには、次のように書かれています-

try または catch コードの実行中に JVM が終了すると、finally ブロックが実行されない場合があります。同様に、try または catch コードを実行しているスレッドが中断または強制終了された場合、アプリケーション全体が続行されても、finally ブロックが実行されない可能性があります。

于 2014-10-13T21:51:50.630 に答える
10

はい、呼び出されます。これが、finally キーワードを使用するポイントです。try/catch ブロックからジャンプして finally ブロックをスキップできる場合、それは System.out.println を try/catch の外に置くのと同じです。

于 2008-09-15T17:46:40.043 に答える
10

答えは簡単ですYES .

入力:

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");
}

出力:

catch
finally
于 2016-08-13T07:00:38.443 に答える
9

はい、そうなります。System.exit() が呼び出されたり、JVM がクラッシュしたりしない限り、try または catch ブロックで何が起こっても問題ありません。ブロックに return ステートメントがある場合、最後にその return ステートメントの前に実行されます。

于 2013-08-16T12:00:20.937 に答える
8

はい。JVM が終了またはクラッシュする場合のみ、そうではありません。

于 2014-01-14T22:29:17.323 に答える
7

最終的にtryブロックのreturnを置き換える場合のreturnに関するポイントに加えて、例外についても同じことが言えます。例外をスローするfinallyブロックは、tryブロック内からスローされたリターンまたは例外を置き換えます。

于 2008-10-01T15:15:44.153 に答える
7

これは実際にはどの言語でも当てはまります...最後に、return がメソッド本体のどこにあるかに関係なく、return ステートメントの前に常に実行されます。そうでなければ、finally ブロックはあまり意味がありません。

于 2008-09-15T18:03:05.637 に答える
7

さまざまなフォーラムで提供されたすべての回答に非常に混乱し、最終的にコーディングして確認することにしました。出力は次のとおりです。

try と catch ブロックで return があっても、finally が実行されます。

try {  
  System.out.println("try"); 
  return;
  //int  i =5/0;
  //System.exit(0 ) ;
} catch (Exception e) {   
  System.out.println("catch");
  return;
  //int  i =5/0;
  //System.exit(0 ) ;
} finally {  
   System.out.println("Print me FINALLY");
}

出力

試す

最後に私を印刷してください

  1. System.exit(0)上記のコードの try および catch ブロックでreturn が に置き換えられ、その前に何らかの理由で例外が発生した場合。
于 2015-05-13T11:11:01.483 に答える
5

例外がスローされた場合、finally が実行されます。例外がスローされない場合、finally が実行されます。例外がキャッチされると、最終的に実行されます。例外がキャッチされない場合、finally が実行されます。

実行されないのは、JVM が終了するときだけです。

于 2011-10-13T16:01:55.700 に答える
4

このコードを試してみると、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;
    }
}
于 2012-04-17T09:06:56.140 に答える
4

finally ブロックは、例外処理の有無にかかわらず常に実行されます。try ブロックの前に何らかの例外が発生した場合、finally ブロックは実行されません。

于 2014-02-17T08:48:25.997 に答える
3

ファイナルはどんな場合でも常に呼び出されるからです。例外はありません、それはまだ呼び出されます、例外をキャッチします、それはまだ呼び出されます

于 2010-05-13T06:19:47.347 に答える
3

finallyネストされたブロックException内で anがthrownの場合、途中で終了することもあります。コンパイラは、ブロックが正常に完了しないことを警告するか、到達できないコードがあるというエラーを出します。到達不能コードのエラーは、 が条件ステートメントの後ろまたはループ内にない場合にのみ表示されます。finallyfinallythrow

try{
}finally{
   try{
   }finally{
      //if(someCondition) --> no error because of unreachable code
      throw new RunTimeException();
   }
   int a = 5;//unreachable code
}
于 2016-04-28T22:11:32.080 に答える
3

通常の実行過程でこれを考慮してください (つまり、例外がスローされていない場合): メソッドが 'void' でない場合、メソッドは常に明示的に何かを返しますが、最終的には常に実行されます。

于 2010-05-13T11:50:14.550 に答える
2

finally ブロックをバイパスできるいくつかの条件を次に示します。

  1. try または catch コードの実行中に JVM が終了すると、finally ブロックが実行されない場合があります。太陽のチュートリアルの詳細
  2. 通常のシャットダウン - これは、デーモン以外の最後のスレッドが終了したとき、または Runtime.exit() (いくつかの良いブログ) のときに発生します。スレッドが終了すると、JVM は実行中のスレッドのインベントリを実行し、残っているスレッドがデーモン スレッドだけの場合は、正常なシャットダウンを開始します。JVM が停止すると、残りのデーモン スレッドはすべて放棄され、最終的にブロックは実行されず、スタックは巻き戻されず、JVM はただ終了します。デーモン スレッドは慎重に使用する必要があります。クリーンアップなしでいつでも安全に放棄できる処理アクティビティはほとんどありません。特に、何らかの種類の I/O を実行する可能性のあるタスクにデーモン スレッドを使用するのは危険です。デーモン スレッドは、メモリ内キャッシュから期限切れのエントリを定期的に削除するバックグラウンド スレッドなどの「ハウスキーピング」タスク用に保存するのが最適です ( source )

最後の非デーモン スレッドの終了例:

public class TestDaemon {
    private static Runnable runnable = new Runnable() {
        @Override
        public void run() {
            try {
                while (true) {
                    System.out.println("Is alive");
                    Thread.sleep(10);
                    // throw new RuntimeException();
                }
            } catch (Throwable t) {
                t.printStackTrace();
            } finally {
                System.out.println("This will never be executed.");
            }
        }
    };

    public static void main(String[] args) throws InterruptedException {
        Thread daemon = new Thread(runnable);
        daemon.setDaemon(true);
        daemon.start();
        Thread.sleep(100);
        // daemon.stop();
        System.out.println("Last non-daemon thread exits.");
    }
}

出力:

Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Last non-daemon thread exits.
Is alive
Is alive
Is alive
Is alive
Is alive
于 2019-08-07T21:53:58.210 に答える
1

リソースの試行例

static class IamAutoCloseable implements AutoCloseable {
    private final String name;
    IamAutoCloseable(String name) {
        this.name = name;
    }
    public void close() {
        System.out.println(name);
    }
}

@Test
public void withResourceFinally() {
    try (IamAutoCloseable closeable1 = new IamAutoCloseable("closeable1");
         IamAutoCloseable closeable2 = new IamAutoCloseable("closeable2")) {
        System.out.println("try");
    } finally {
        System.out.println("finally");
    }
}

テスト出力:

try
closeable2
closeable1
finally
于 2020-02-08T04:45:25.507 に答える