考虑到这段代码,我能绝对确定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将不执行:

案例1:

执行System.exit()时。

案例2:

当JVM/线程崩溃时。

案例3:

手动停止执行时。

其他回答

在正常的执行过程中考虑这一点(即不抛出任何异常):如果方法不是“void”,那么它总是显式返回一些东西,然而,最终总是执行

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

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

公认的答案在几乎所有方面都是正确的,但它仍然只是事实的一半(好吧,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块始终正常终止,否则它是否始终被执行可能无关紧要…

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

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

无论异常处理与否,Finally块始终执行。如果在try块之前发生任何异常,那么Finally块将不会执行。