考虑到这段代码,我能绝对确定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");
}
当前回答
在两种独特的情况下,返回后不会调用finally块:如果首先调用System.exit(),或者JVM崩溃。
让我尽量用最简单的方式回答你的问题。
规则1:finally块始终运行(虽然有例外。但让我们坚持一段时间。)
规则2:当控件离开try或catch块时,finally块中的语句会运行。控制权的转移可能是正常执行、break、continue、goto或return语句的执行或异常传播的结果。
在返回语句的情况下(由于其标题),控件必须离开调用方法,因此调用相应try finally结构的finally块。return语句在finally块之后执行。
如果finally块中也有return语句,它肯定会覆盖try块中挂起的语句,因为它会清除调用堆栈。
您可以在此处找到更好的解释:http://msdn.microsoft.com/en-us/....这一概念在所有高级语言中基本相同。
其他回答
如果抛出异常,则最终运行。如果未引发异常,则最终运行。如果捕获到异常,则最终运行。如果未捕获异常,则最终运行。
只有当JVM退出时,它才不会运行。
公认的答案在几乎所有方面都是正确的,但它仍然只是事实的一半(好吧,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块。大多数开发人员使用此块来关闭数据库连接、resultset对象、语句对象,还使用到java休眠来回滚事务。
是的,因为没有控制语句可以阻止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
}
}
在两种独特的情况下,返回后不会调用finally块:如果首先调用System.exit(),或者JVM崩溃。
让我尽量用最简单的方式回答你的问题。
规则1:finally块始终运行(虽然有例外。但让我们坚持一段时间。)
规则2:当控件离开try或catch块时,finally块中的语句会运行。控制权的转移可能是正常执行、break、continue、goto或return语句的执行或异常传播的结果。
在返回语句的情况下(由于其标题),控件必须离开调用方法,因此调用相应try finally结构的finally块。return语句在finally块之后执行。
如果finally块中也有return语句,它肯定会覆盖try块中挂起的语句,因为它会清除调用堆栈。
您可以在此处找到更好的解释:http://msdn.microsoft.com/en-us/....这一概念在所有高级语言中基本相同。