考虑到这段代码,我能绝对确定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关键字的全部意义。如果跳出try/catch块可以跳过finally块,这与将System.out.println放在try/catch之外相同。
其他回答
示例代码:
public static void main(String[] args) {
System.out.println(Test.test());
}
public static int test() {
try {
return 0;
}
finally {
System.out.println("something is printed");
}
}
输出:
something is printed.
0
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块将运行,异常将继续传播。
考虑以下程序:
public class SomeTest {
private static StringBuilder sb = new StringBuilder();
public static void main(String args[]) {
System.out.println(someString());
System.out.println("---AGAIN---");
System.out.println(someString());
System.out.println("---PRINT THE RESULT---");
System.out.println(sb.toString());
}
private static String someString() {
try {
sb.append("-abc-");
return sb.toString();
} finally {
sb.append("xyz");
}
}
}
从Java 1.8.162开始,上述代码块提供以下输出:
-abc-
---AGAIN---
-abc-xyz-abc-
---PRINT THE RESULT---
-abc-xyz-abc-xyz
这意味着使用finally释放对象是一种很好的做法,如以下代码所示:
private static String someString() {
StringBuilder sb = new StringBuilder();
try {
sb.append("abc");
return sb.toString();
} finally {
sb = null; // Just an example, but you can close streams or DB connections this way.
}
}
公认的答案在几乎所有方面都是正确的,但它仍然只是事实的一半(好吧,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块中有一个return语句,它将胜过常规块中的任何其他返回。也就是说,以下块将返回false:
try { return true; } finally { return false; }
从finally块抛出异常也是一样的。