考虑到这段代码,我能绝对确定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");
}

当前回答

示例代码:

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

其他回答

这是Java语言规范中的官方词汇。

14.20.2.执行try finally和try catch finally

带有finally块的try语句通过首先执行try块来执行。然后有一个选择:如果try块的执行正常完成,[…]如果try块的执行因抛出值V而突然完成,[…]如果由于任何其他原因R,try块的执行突然完成,则执行finally块。然后有一个选择:如果finally块正常完成,则try语句由于原因R而突然完成。如果finally块因原因S而突然完成,则try语句因原因S突然完成(并且原因R被丢弃)。

返回的规范实际上明确了这一点:

JLS 14.17退货声明

退货声明:返回表达式(opt);没有表达式的return语句试图将控制传递给包含它的方法或构造函数的调用者。带有表达式的return语句试图将控制权传递给包含它的方法的调用者;表达式的值变为方法调用的值。前面的描述说的是“试图传递控制”而不仅仅是“传递控制”,因为如果在方法或构造函数中有任何try语句,其try块包含return语句,那么在将控制传递给方法或构造函数的调用程序之前,这些try语句的任何finally子句都将按从内到外的顺序执行。finally子句的突然完成可能会中断由return语句发起的控制权转移。

简而言之,在官方Java文档(单击此处)中-

如果JVM在执行try或catch代码时退出,则finally块可能不执行。同样,如果线程执行try-or-catch代码被中断或终止,finally块可能即使应用程序作为一个整体继续,也不会执行。

除非由于JVM崩溃或调用System.exit(0)而导致程序异常终止,否则finally块将始终执行。

除此之外,finally块中返回的任何值都将覆盖finally块执行之前返回的值,因此在使用try finally时,请注意检查所有退出点。

以下是一些可以绕过finally块的条件:

如果在执行try或catch代码时JVM退出,那么finally块可能不会执行。更多太阳教程正常关闭-当最后一个非守护程序线程退出时,或者当Runtime.exit()(一些不错的博客)时,都会发生这种情况。当线程退出时,JVM会对正在运行的线程进行盘点,如果只剩下守护进程线程,则会启动有序关闭。当JVM停止时,所有剩余的守护程序线程都将被放弃。如果不执行块,堆栈也不会被解开,JVM只会退出。守护程序线程应该很少使用,很少有处理活动可以在任何时候安全地放弃,而无需清理。特别是,将守护程序线程用于可能执行任何类型I/O的任务是危险的。守护程序线程最好保存用于“内务管理”任务,例如后台线程,它定期从内存缓存中删除过期条目(源)

最后一个非守护程序线程退出示例:

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

最终将执行,这是肯定的。

在以下情况下,finally将不执行:

案例1:

执行System.exit()时。

案例2:

当JVM/线程崩溃时。

案例3:

手动停止执行时。