考虑到这段代码,我能绝对确定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块总是执行的吗,不管something()是什么?
try {
something();
return success;
}
catch (Exception e) {
return failure;
}
finally {
System.out.println("I don't know if this will get printed out");
}
当前回答
公认的答案在几乎所有方面都是正确的,但它仍然只是事实的一半(好吧,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块中执行因此,如果try块中的代码试图返回一个值或抛出一个异常,则该项将被“搁置”,直到finally块可以执行因为finally块中的代码(根据定义)具有高优先级,所以它可以返回或抛出任何它喜欢的东西。在这种情况下,“搁在架子上”的任何东西都会被丢弃。唯一的例外是,如果VM在try块期间完全关闭,例如通过“System.exit”
finally块总是在返回x(计算)值之前执行。
System.out.println("x value from foo() = " + foo());
...
int foo() {
int x = 2;
try {
return x++;
} finally {
System.out.println("x value in finally = " + x);
}
}
输出:
最终x值=3来自foo()的x值=2
试用间苯二酚示例
static class IamAutoCloseable implements AutoCloseable {
private final String name;
IamAutoCloseable(String name) {
this.name = name;
}
public void close() {
System.out.println(name);
}
}
@Test
public void withResourceFinally() {
try (IamAutoCloseable closeable1 = new IamAutoCloseable("closeable1");
IamAutoCloseable closeable2 = new IamAutoCloseable("closeable2")) {
System.out.println("try");
} finally {
System.out.println("finally");
}
}
测试输出:
try
closeable2
closeable1
finally
如果抛出异常,则最终运行。如果未引发异常,则最终运行。如果捕获到异常,则最终运行。如果未捕获异常,则最终运行。
只有当JVM退出时,它才不会运行。