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

当前回答

这是因为您将i的值指定为12,但没有将i的返回给函数。正确的代码如下:

public static int test() {
    int i = 0;
    try {
        return i;
    } finally {
        i = 12;
        System.out.println("finally trumps return.");
        return i;
    }
}

其他回答

公认的答案在几乎所有方面都是正确的,但它仍然只是事实的一半(好吧,95%的事实)。

假设以下代码:

private final Lock m_Lock = new ReentrantLock();
…
public final SomeObject doSomething( final SomeObject arg )
{
  final SomeObject retValue;
  try
  {
    lock.lock();
    retValue = SomeObject( arg );
  }
  finally
  {
    out.println( "Entering finally block");
    callingAnotherMethod( arg, retValue );
    lock.unlock();
  }
  
  return retValue;
}
…
try
{
   final var result = doSomething( new SomeObject() );
}
catch( final StackOverflowError e ) { /* Deliberately ignored */ }

调用doSomething()方法将几乎立即导致StackOverflowError。

锁也不会松开!

但是,当finally块总是被执行时(接受的答案中已经列出了例外情况),这怎么会发生呢?

这是因为不能保证finally块中的所有语句都真正执行!

如果在调用lock.unlock()之前调用System.exit()或throws语句,这将是显而易见的。

但示例代码中没有类似的内容…

除此之外,调用lock.unlock()之前finally块中的另外两个方法调用将导致另一个StackOverflowError…

瞧,锁没有松开!

虽然这样的示例代码很愚蠢,但在许多类型的软件中都可以找到类似的模式。只要最后一个街区没有发生什么丑恶的事情,一切都会好起来的…

有趣的事实是,它在Java的更高版本中不起作用(这意味着在更高的版本中,锁被释放了…)。不知道何时以及为什么会发生变化。

但您仍然必须确保finally块始终正常终止,否则它是否始终被执行可能无关紧要…

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

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

案例1:

执行System.exit()时。

案例2:

当JVM/线程崩溃时。

案例3:

手动停止执行时。

因为除非调用System.exit()(否则线程崩溃),否则将始终调用finally块。

这就是最后一块的全部想法。当然,它可以让你确保你做了清理,否则可能会因为你回来而被跳过。

不管try块中发生了什么,最终都会被调用(除非您调用System.exit(int)或Java虚拟机因其他原因退出)。

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块将运行,异常将继续传播。