finallyブロックは常にJavaで実行されますか?

2008年09月16日に質問されました。  ·  閲覧回数 519.6k回  ·  ソース

jonny five picture
2008年09月16日

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

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

回答

jodonnell picture
2008年09月16日
2775

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

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

  1. System.exit()を呼び出す場合
  2. Runtime.getRuntime().halt(exitStatus)を呼び出す場合
  3. JVMが最初にクラッシュした場合
  4. JVMがtryまたはcatchブロックで無限ループ(またはその他の中断不可能で終了しないステートメント)に到達した場合
  5. OSがJVMプロセスを強制的に終了した場合。 例:UNIXではkill -9 <pid>
  6. ホストシステムが停止した場合。 例:停電、ハードウェアエラー、OSパニックなど
  7. finallyブロックがデーモンスレッドによって実行され、 finallyが呼び出される前に、他のすべての非デーモンスレッドが終了する場合
Kevin picture
2008年09月16日
587

コード例:

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

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

出力:

finally trumps return. 
0
MooBob42 picture
2008年09月16日
400

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

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

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

polygenelubricants picture
2010年05月25日
259

これがJava言語仕様の公式の言葉です。

14.20.2。

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

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

returnの仕様は、実際にはこれを明示的にしています。

JLS 14.17returnステートメント

ReturnStatement:
     return Expression(opt) ;

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

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

前述の説明は、任意のある場合ので、「転送制御を試み」だけでなく「転送が制御」と言うtryメソッドやコンストラクタ内のステートメントtryブロック含有return次に、これらのtryステートメントのfinally句は、メソッドまたはコンストラクターの呼び出し元に制御が移される前に、最も内側から最も外側の順に実行されます。 finally句が突然完了すると、 returnステートメントによって開始された制御の転送が中断される可能性があります。

Eyal Schneider picture
2010年05月13日
167

他の応答に加えて、「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();
    }
}
WoodenKitty picture
2013年12月04日
122

これがケビンの答えの詳細です。 返される式は、後で返される場合でも、 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
vibhash picture
2008年11月18日
121

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

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が割り当てられます。

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

あなたはEclipseでこのコードをデバッグする場合は、あなたが実行した後のことを感じ取得しますSystem.outfinally阻止returnの文でtryブロックが実行されます再び。 しかし、そうではありません。 単に値2を返します。

Chris Cooper picture
2010年05月13日
54

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

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

Garth Gilmour picture
2008年09月16日
42

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

  1. finishブロックに配置されたコードは、tryブロック内で発生するものは何でも実行
  2. したがって、tryブロックのコードが値を返そうとしたり、例外をスローしたりしようとすると、finallyブロックが実行できるようになるまで、アイテムは「シェルフに」配置されます。
  3. finishブロックのコードは(定義上)優先度が高いため、好きなものを返したりスローしたりできます。 その場合、「棚に残っている」ものはすべて破棄されます。
  4. これに対する唯一の例外は、たとえば「System.exit」によって、tryブロック中にVMが完全にシャットダウンした場合です。
shyam picture
2008年09月16日
21

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