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

当前回答

除了最后替换try块中的返回之外,异常也是如此。引发异常的finally块将替换try块中引发的返回或异常。

其他回答

是的,因为没有控制语句可以阻止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
    }
}

不总是这样

Java语言规范描述了try-catch finally和try-catch块在14.20.2在任何地方,它都不会指定始终执行finally块。但对于try-catch-finally和try-finally块完成的所有情况,它确实指定在完成之前必须执行finally。

try {
  CODE inside the try block
}
finally {
  FIN code inside finally block
}
NEXT code executed after the try-finally block (may be in a different method).

JLS不保证在CODE之后执行FIN。JLS保证,如果执行CODE和NEXT,则FIN将始终在CODE之后和NEXT之前执行。

为什么JLS不能保证finally块总是在try块之后执行?因为这是不可能的。在完成try块之后但在执行finally块之前,JVM不太可能被中止(终止、崩溃、断电)。JLS无法避免这种情况。

因此,任何软件的正常行为都取决于最终块,总是在其尝试块完成后执行。

try块中的返回指令与此问题无关。如果执行在try-catch finally之后到达代码,则可以保证finally块之前已经执行过,无论是否在try块内有返回指令。

我尝试了上面的示例,但稍作修改-

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.

这是因为当返回i;i的值为2。在此之后,执行finally块,其中12被分配给i,然后执行System.out-out。

在执行finally块之后,try块返回2,而不是返回12,因为该返回语句不会再次执行。

如果您将在Eclipse中调试此代码,那么您会感觉到在执行System.out of finally块之后,try块的返回语句将再次执行。但事实并非如此。它只返回值2。

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

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

案例1:

执行System.exit()时。

案例2:

当JVM/线程崩溃时。

案例3:

手动停止执行时。

此外,虽然这是一种糟糕的做法,但如果finally块中有一个return语句,它将胜过常规块中的任何其他返回。也就是说,以下块将返回false:

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

从finally块抛出异常也是一样的。