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

当前回答

是的,因为没有控制语句可以阻止finally被执行。

下面是一个参考示例,其中将执行所有代码块:

| x | Current result | Code 
|---|----------------|------ - - -
|   |                |     
|   |                | public static int finallyTest() {
| 3 |                |     int x = 3;
|   |                |     try {
|   |                |        try {
| 4 |                |             x++;
| 4 | return 4       |             return x;
|   |                |         } finally {
| 3 |                |             x--;
| 3 | throw          |             throw new RuntimeException("Ahh!");
|   |                |         }
|   |                |     } catch (RuntimeException e) {
| 4 | return 4       |         return ++x;
|   |                |     } finally {
| 3 |                |         x--;
|   |                |     }
|   |                | }
|   |                |
|---|----------------|------ - - -
|   | Result: 4      |

在下面的变体中,返回x;将跳过。结果仍然是4:

public static int finallyTest() {
    int x = 3;
    try {
        try {
            x++;
            if (true) throw new RuntimeException("Ahh!");
            return x; // skipped
        } finally {
            x--;
        }
    } catch (RuntimeException e) {
        return ++x;
    } finally {
        x--;
    }
}

当然,引用可以跟踪其状态。此示例返回值为4的引用:

static class IntRef { public int value; }
public static IntRef finallyTest() {
    IntRef x = new IntRef();
    x.value = 3;
    try {
        return x;
    } finally {
        x.value++; // will be tracked even after return
    }
}

其他回答

答案很简单:是。

输入:

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

Finally is always run这就是重点,只是因为它出现在返回后的代码中并不意味着它就是这样实现的。Java运行时有责任在退出try块时运行此代码。

例如,如果您有以下内容:

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

运行时将生成如下内容:

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

如果抛出未捕获的异常,finally块将运行,异常将继续传播。

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

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

案例1:

执行System.exit()时。

案例2:

当JVM/线程崩溃时。

案例3:

手动停止执行时。

我很晚才回答,但我很惊讶没有人提到Java调试器选项来删除堆栈帧。我是IntelliJ中此功能的重度用户。(我确信Eclipse和NetBeans支持相同的功能。)

如果我从后面跟着finally块的try或catch块中删除堆栈帧,IDE将提示我:“我要执行finally块吗?”显然,这是一个人工运行时环境——调试器!

为了回答您的问题,我想说,只有在连接调试器时忽略,并且(就像其他人所说的)method something()不(a)通过JNI调用Java方法System.exit(int)或(b)C函数exit(int/abort(),或(C)对自身执行类似于调用kill-9$PID(!)的疯狂操作时,才能保证它运行。

是的,finally将在执行try或catch代码块后调用。

唯一不会被调用的时间是:

如果调用System.exit()如果调用Runtime.getRuntime().hart(exitStatus)如果JVM首先崩溃如果JVM到达try或catch块中的无限循环(或其他一些不可中断、不终止的语句)如果操作系统强制终止JVM进程;例如,在UNIX上,kill-9<pid>如果主机系统失效;例如,电源故障、硬件错误、操作系统死机等如果finally块将由守护程序线程执行,并且所有其他非守护程序线程在finally调用之前退出