finally {}块不会执行的情况是什么?

时间:2021-08-12 22:12:27

In a Java try{} ... catch{} ... finally{} block, code within the finally{} is generally considered "guaranteed" to run regardless of what occurs in the try/catch. However, I know of at least two circumstances under which it will not execute:

在Java try {} ... catch {} ... finally {}块中,finally {}中的代码通常被认为是“保证”运行,无论try / catch中发生了什么。但是,我知道至少有两种情况不会执行:

  • If System.exit(0) is called; or,
  • 如果调用System.exit(0);要么,

  • if an Exception is thrown all the way up to the JVM and the default behavior occurs (i.e., printStackTrace() and exit)
  • 如果异常被抛到JVM并且发生默认行为(即printStackTrace()并退出)

Are there any other program behaviors that will prevent the code in a finally{} block from executing? Under what specific conditions will the code execute or not?

是否有任何其他程序行为会阻止finally {}块中的代码执行?代码在什么具体条件下执行?

EDIT: As NullUserException pointed out, the second case is actually not true. I thought it was because the text in standard error printed after that in standard out, preventing the text from being seen without scrolling up. :) Apologies.

编辑:正如NullUserException指出的那样,第二种情况实际上并非如此。我认为这是因为标准错误中的文本在标准输出之后打印出来,防止文本在没有向上滚动的情况下被看到。 :) 道歉。

9 个解决方案

#1


32  

If you call System.exit() the program exits immediately without finally being called.

如果你调用System.exit(),程序会立即退出而不会被调用。

A JVM Crash e.g. Segmentation Fault, will also prevent finally being called. i.e. the JVM stops immediately at this point and produces a crash report.

JVM崩溃,例如分段错误,也会阻止最终被调用。即JVM此时立即停止并生成崩溃报告。

An infinite loop would also prevent a finally being called.

无限循环也会阻止最终被调用。

The finally block is always called when a Throwable is thrown. Even if you call Thread.stop() which triggers a ThreadDeath to be thrown in the target thread. This can be caught (it's an Error) and the finally block will be called.

抛出Throwable时始终会调用finally块。即使你调用Thread.stop(),它也会触发在目标线程中抛出ThreadDeath。这可以被捕获(这是一个错误)并且将调用finally块。


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

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 test*() {
    try {
        try {
            test*0();
        } finally {
            System.out.print("finally called after ");
        }
    } catch (Throwable t) {
        System.out.println(t);
    }
}

private static void test*0() {
    test*0();
}

prints

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.*Error

Note: in each case the thread kept running, even after SO, OOME, Interrupted and Thread.stop()!

注意:在每种情况下,线程都保持运行,即使在SO,OOME,Interrupted和Thread.stop()之后!

#2


9  

Infinite loop in the try block.

try块中的无限循环。

Corrupt RAM? Program no longer runs as written? I've actually debugged that once on a DOS machine.

损坏内存?程序不再按书面形式运行?我实际上已经在DOS机器上调试了一次。

#3


1  

There is a chance of partial execution when finally itself throws an exception (or leads to an error)

当最终自身抛出异常(或导致错误)时,有可能部分执行

#4


1  

One could be "A finally is a part of daeomon thread it may not be executed".

一个可能是“最终是daeomon线程的一部分,它可能无法执行”。

#5


1  

The only times finally won't be called are:

最终不会被召唤的唯一时间是:

if the power turns off

如果电源关闭

  1. if you call System.exit()
  2. 如果你调用System.exit()

  3. if the JVM crashes first
  4. 如果JVM首先崩溃

  5. if there is an infinite loop in the try block
  6. 如果try块中有无限循环

  7. if the power turns off
  8. 如果电源关闭

#6


1  

Testing the finally block in different statement in try block.

在try块中的不同语句中测试finally块。

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

Statements in which finally block is executed are following:

执行finally块的语句如下:

  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. If there is any exception occurred.
  8. 如果发生任何异常。

  9. If there is no exception.
  10. 如果没有例外。

Statements in which finally block is not executed are following:

不执行finally块的语句如下:

  1. Thread.currentThread().suspend();
  2. System.exit(0);
  3. JVM crashed.
  4. Power to CPU chip goes off.
  5. CPU芯片的电源关闭。

  6. OS kills JVM process.
  7. 操作系统杀死了JVM进程。

  8. Runtime.getRuntime().exit(0);
  9. Runtime.getRuntime().halt(0);

#7


0  

I think when JVM exits suddenly due to any reason, that can be a cause the control will not enter into the the finally block and never execute.

我认为当JVM由于任何原因突然退出时,这可能是因为控件不会进入finally块而永远不会执行。

#8


0  

You can make it a part of Daemon Thread. You may use the method setDaemon(boolean status) which is used to mark the current thread as daemon thread or user thread and exit the JVM as and when required. This will enable you exit the JVM before finally{} is executed.

您可以将其作为守护程序线程的一部分。您可以使用setDaemon(boolean status)方法,该方法用于将当前线程标记为守护程序线程或用户线程,并在需要时退出JVM。这将使您能够在执行finally {}之前退出JVM。

#9


0  

Another possible instance of a finally block never executing would be due to a design where the method returned before the try block was entered, as in the cases of some very bad code I've seen from time to time:

finally块永远不会执行的另一个可能的实例是由于在输入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...
    }

I know none of you would ever do this, so I hesitated to add this as a possible scenario, but thought, eh, it's Friday, what the heck ; )

我知道你们中没有人会这样做,所以我犹豫是否可以将此作为一种可能的情况加入,但是,想想,呃,这是星期五,到底是什么; )

#1


32  

If you call System.exit() the program exits immediately without finally being called.

如果你调用System.exit(),程序会立即退出而不会被调用。

A JVM Crash e.g. Segmentation Fault, will also prevent finally being called. i.e. the JVM stops immediately at this point and produces a crash report.

JVM崩溃,例如分段错误,也会阻止最终被调用。即JVM此时立即停止并生成崩溃报告。

An infinite loop would also prevent a finally being called.

无限循环也会阻止最终被调用。

The finally block is always called when a Throwable is thrown. Even if you call Thread.stop() which triggers a ThreadDeath to be thrown in the target thread. This can be caught (it's an Error) and the finally block will be called.

抛出Throwable时始终会调用finally块。即使你调用Thread.stop(),它也会触发在目标线程中抛出ThreadDeath。这可以被捕获(这是一个错误)并且将调用finally块。


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

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 test*() {
    try {
        try {
            test*0();
        } finally {
            System.out.print("finally called after ");
        }
    } catch (Throwable t) {
        System.out.println(t);
    }
}

private static void test*0() {
    test*0();
}

prints

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.*Error

Note: in each case the thread kept running, even after SO, OOME, Interrupted and Thread.stop()!

注意:在每种情况下,线程都保持运行,即使在SO,OOME,Interrupted和Thread.stop()之后!

#2


9  

Infinite loop in the try block.

try块中的无限循环。

Corrupt RAM? Program no longer runs as written? I've actually debugged that once on a DOS machine.

损坏内存?程序不再按书面形式运行?我实际上已经在DOS机器上调试了一次。

#3


1  

There is a chance of partial execution when finally itself throws an exception (or leads to an error)

当最终自身抛出异常(或导致错误)时,有可能部分执行

#4


1  

One could be "A finally is a part of daeomon thread it may not be executed".

一个可能是“最终是daeomon线程的一部分,它可能无法执行”。

#5


1  

The only times finally won't be called are:

最终不会被召唤的唯一时间是:

if the power turns off

如果电源关闭

  1. if you call System.exit()
  2. 如果你调用System.exit()

  3. if the JVM crashes first
  4. 如果JVM首先崩溃

  5. if there is an infinite loop in the try block
  6. 如果try块中有无限循环

  7. if the power turns off
  8. 如果电源关闭

#6


1  

Testing the finally block in different statement in try block.

在try块中的不同语句中测试finally块。

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

Statements in which finally block is executed are following:

执行finally块的语句如下:

  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. If there is any exception occurred.
  8. 如果发生任何异常。

  9. If there is no exception.
  10. 如果没有例外。

Statements in which finally block is not executed are following:

不执行finally块的语句如下:

  1. Thread.currentThread().suspend();
  2. System.exit(0);
  3. JVM crashed.
  4. Power to CPU chip goes off.
  5. CPU芯片的电源关闭。

  6. OS kills JVM process.
  7. 操作系统杀死了JVM进程。

  8. Runtime.getRuntime().exit(0);
  9. Runtime.getRuntime().halt(0);

#7


0  

I think when JVM exits suddenly due to any reason, that can be a cause the control will not enter into the the finally block and never execute.

我认为当JVM由于任何原因突然退出时,这可能是因为控件不会进入finally块而永远不会执行。

#8


0  

You can make it a part of Daemon Thread. You may use the method setDaemon(boolean status) which is used to mark the current thread as daemon thread or user thread and exit the JVM as and when required. This will enable you exit the JVM before finally{} is executed.

您可以将其作为守护程序线程的一部分。您可以使用setDaemon(boolean status)方法,该方法用于将当前线程标记为守护程序线程或用户线程,并在需要时退出JVM。这将使您能够在执行finally {}之前退出JVM。

#9


0  

Another possible instance of a finally block never executing would be due to a design where the method returned before the try block was entered, as in the cases of some very bad code I've seen from time to time:

finally块永远不会执行的另一个可能的实例是由于在输入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...
    }

I know none of you would ever do this, so I hesitated to add this as a possible scenario, but thought, eh, it's Friday, what the heck ; )

我知道你们中没有人会这样做,所以我犹豫是否可以将此作为一种可能的情况加入,但是,想想,呃,这是星期五,到底是什么; )