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

当前回答

与以下代码相同:

static int f() {
    while (true) {
        try {
            return 1;
        } finally {
            break;
        }
    }
    return 2;
}

f将返回2!

其他回答

公认的答案在几乎所有方面都是正确的,但它仍然只是事实的一半(好吧,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{
    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

最后总是执行Block。除非和直到存在System.exit()语句(finally块中的第一条语句)。如果system.exit()是第一条语句,那么finally块将不会被执行,控制权将从finally块中释放出来。每当System.exit()语句进入finally块,直到该语句最终执行块,当System.exit)出现时,控制力完全从finally块中释放出来。

是的,它会被呼叫。这就是拥有finally关键字的全部意义。如果跳出try/catch块可以跳过finally块,这与将System.out.println放在try/catch之外相同。

此外,finally的返回将丢弃任何异常。http://jamesjava.blogspot.com/2006/03/dont-return-in-finally-clause.html