web-dev-qa-db-ja.com

finally {}ブロックが実行されない状況は何ですか?

Java _try{} ... catch{} ... finally{}_ブロックでは、_finally{}_内のコードは、try/catchで何が発生しても、実行が「保証されている」と一般に見なされています。しかし、 実行されない少なくとも2つの状況:

  • System.exit(0)が呼び出された場合;または、
  • 例外がJVMまでスローされ、デフォルトの動作が発生した場合(つまり、printStackTrace()で終了)

_finally{}_ブロックのコードの実行を妨げる他のプログラムの動作はありますか?コードはどの特定の条件下で実行されますか?

編集: NullUserExceptionが指摘したように、2番目のケースは実際には当てはまりません。標準エラーのテキストが標準出力で印刷され、上にスクロールしないとテキストが表示されないためだと思いました。 :)謝罪。

32
asteri

System.exit() を呼び出すと、finallyが呼び出されずにプログラムが即座に終了します。

JVMクラッシュ(例:セグメンテーション違反は、最終的に呼び出されることも防ぎます。つまり、JVMはこの時点ですぐに停止し、クラッシュレポートを生成します。

無限ループも、finallyが呼び出されるのを防ぎます。

Throwableがスローされると、finallyブロックが常に呼び出されます。 ThreadDeath をトリガーするThread.stop()を呼び出しても、ターゲットスレッドでスローされます。これはキャッチでき( Error です)、finallyブロックが呼び出されます。


public static void main(String[] args) {
    testOutOfMemoryError();
    testThreadInterrupted();
    testThreadStop();
    testStackOverflow();
}

private static void testThreadStop() {
    try {
        try {
            final Thread thread = Thread.currentThread();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    thread.stop();
                }
            }).start();
            while(true)
                Thread.sleep(1000);
        } finally {
            System.out.print("finally called after ");
        }
    } catch (Throwable t) {
        System.out.println(t);
    }
}

private static void testThreadInterrupted() {
    try {
        try {
            final Thread thread = Thread.currentThread();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    thread.interrupt();
                }
            }).start();
            while(true)
                Thread.sleep(1000);
        } finally {
            System.out.print("finally called after ");
        }
    } catch (Throwable t) {
        System.out.println(t);
    }
}

private static void testOutOfMemoryError() {
    try {
        try {
            List<byte[]> bytes = new ArrayList<byte[]>();
            while(true)
                bytes.add(new byte[8*1024*1024]);
        } finally {
            System.out.print("finally called after ");
        }
    } catch (Throwable t) {
        System.out.println(t);
    }
}

private static void testStackOverflow() {
    try {
        try {
            testStackOverflow0();
        } finally {
            System.out.print("finally called after ");
        }
    } catch (Throwable t) {
        System.out.println(t);
    }
}

private static void testStackOverflow0() {
    testStackOverflow0();
}

プリント

finally called after Java.lang.OutOfMemoryError: Java heap space
finally called after Java.lang.InterruptedException: sleep interrupted
finally called after Java.lang.ThreadDeath
finally called after Java.lang.StackOverflowError

注:いずれの場合も、SO、OOME、Interrupted、およびThread.stop()の後でも、スレッドは実行され続けます。

33
Peter Lawrey

tryブロックの無限ループ。

破損したRAM?プログラムは記述どおりに実行されなくなりましたか?私は実際にDOSマシンで一度デバッグしました。

9

最終的に呼び出されないのは次の場合のみです。

電源が切れた場合

  1. system.exit()を呼び出した場合
  2. jVMが最初にクラッシュした場合
  3. tryブロックに無限ループがある場合
  4. 電源が切れた場合
1
Virendra Singh

最終的にそれ自体が例外をスローする(またはエラーになる)と、部分的に実行される可能性があります。

1
Chris

1つは、「最終的には実行されない可能性があるデーモンスレッドの一部です」のようになります。

1
Tushar Paliwal

Tryブロックの別のステートメントで最終的にブロックをテストします。

_ public static void main(String [] args){

    try{
        System.out.println("Before Statement");
        /*** Statement ***/
        System.out.println("After Statement");
    }
    catch(Exception e){
    }
    finally{
        System.out.println("Finally is Executed");
    }
_

最終的にブロックが実行されるであるステートメントは次のとおりです。

  1. Thread.currentThread().interrupted();
  2. Thread.currentThread().destroy();
  3. Thread.currentThread().stop();
  4. Thread.sleep(10);
  5. Thread.currentThread().interrupt();
  6. Runtime.getRuntime().addShutdownHook(Thread.currentThread());
  7. 例外が発生した場合。
  8. 例外がない場合。

最終的にブロックが実行されないのステートメントは次のとおりです。

  1. Thread.currentThread().suspend();
  2. System.exit(0);
  3. JVMがクラッシュしました。
  4. CPUチップへの電源がオフになります。
  5. OSがJVMプロセスを強制終了します。
  6. Runtime.getRuntime().exit(0);
  7. Runtime.getRuntime().halt(0);
1
Raman Gupta

なんらかの理由でJVMが突然終了した場合、それが原因で、コントロールがfinallyブロックに入らず、実行されないことが考えられます。

0
JDGuide

実行されなかったfinallyブロックのもう1つの可能性のあるインスタンスは、tryブロックに入る前にメソッドが返されるという設計が原因である可能性があります。

public ObjectOfSomeType getMeAnObjectOfSomeType() throws SomeHorrendousException {
    if (checkSomeObjectState()) {
        return new ObjectOfSomeType();
    }

    try {
        // yada yada yada...
    } catch (SomeHorrendousException shexc) {
        // wow, do something about this horrendous exception...
    } finally {
        // do some really important cleanup and state invalidation stuff...
    }

誰もこれをするつもりはないので、これを考えられるシナリオとして追加するのをためらっていましたが、ええと、金曜日です。 )

0
idclaar

デーモンスレッドの一部にすることができます。現在のスレッドをデーモンスレッドまたはユーザースレッドとしてマークし、必要に応じてJVMを終了するために使用されるメソッドsetDaemon(boolean status)を使用できます。これにより、finally{}が実行される前にJVMを終了できます。

0
Sambhav