something()
是什么,finally
语句块总是会被执行?try {
something();
return success;
}
catch (Exception e) {
return failure;
}
finally {
System.out.println("I don't know if this will get printed out");
}
something()
是什么,finally
语句块总是会被执行?try {
something();
return success;
}
catch (Exception e) {
return failure;
}
finally {
System.out.println("I don't know if this will get printed out");
}
try {
} finally {
try {
} finally {
// if (someCondition) --> no error because of unreachable code
throw new RunTimeException();
}
int a = 5; // unreachable code
}
try/catch
中发生了什么,一旦完成,控制流程将会传递到finally块”。try/finally保证本质上就是这样,没有更多也没有更少。在任何块中,无论是try/catch/finally还是其他块,你都可以像你建议的那样嵌套其他的try/catch/finally块。事实上,有些人并不知道这一点。 - Loduwijk由于无论你遇到什么情况,最终总是会调用 finally 块。即使没有异常出现,finally 块仍然会被调用。
与以下代码相同:
static int f() {
while (true) {
try {
return 1;
} finally {
break;
}
}
return 2;
}
f将返回2!
是的,在任何情况下它都会被调用,但是当你使用 System.exit()
时不会被调用。
try {
// risky code
} catch (Exception e) {
// exception handling code
}
finally() {
// It is always executed, but if before this block there is any statement like System.exit(0); then this block will not be executed.
}
无论您在try块中放置了一个return语句,finally块始终会被执行。在return语句之前,finally块将被执行。
最后总是在结尾处调用
当您尝试执行某些代码时,如果try中发生了异常,catch将捕获该异常并可以打印一些消息或抛出错误,然后finally块将被执行。
通常在进行清理时使用finally,例如,如果您在Java中使用扫描仪,则应该关闭扫描仪,因为否则会导致其他问题,例如无法打开某些文件。
最后一个非守护线程退出的示例:
public class TestDaemon {
private static Runnable runnable = new Runnable() {
@Override
public void run() {
try {
while (true) {
System.out.println("Is alive");
Thread.sleep(10);
// throw new RuntimeException();
}
} catch (Throwable t) {
t.printStackTrace();
} finally {
System.out.println("This will never be executed.");
}
}
};
public static void main(String[] args) throws InterruptedException {
Thread daemon = new Thread(runnable);
daemon.setDaemon(true);
daemon.start();
Thread.sleep(100);
// daemon.stop();
System.out.println("Last non-daemon thread exits.");
}
}
Output:
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Last non-daemon thread exits.
Is alive
Is alive
Is alive
Is alive
Is alive
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
被接受的答案在几乎所有方面都是正确的,但它仍然只是真相的一半(好吧,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
。
lock
将不会被释放!
但是,当finally
块总是执行(已在接受的答案中列出的异常除外)时,怎么会发生这种情况呢?
那是因为没有保证finally
块中的所有语句都真正执行!
如果在调用lock.unlock()
之前有一个对System.exit()
或throws
语句的调用,那么这一点就显而易见了。
但是,在示例代码中没有这样的内容...
除此之外,在调用lock.unlock()
之前finally
块中的另外两个方法调用将导致另一个StackOverflowError
...
然后,锁未被释放!
尽管样例代码本身很傻,但类似模式在许多种软件中都可以找到。只要在finally
块中没有发生任何问题,一切都运作正常...
有趣的事实是,它在Java的后续版本中不起作用(意味着在后续版本中,锁被释放了...)。不知道这个什么时候和为什么改变了。
但你仍然必须确保finally
块始终正常终止,否则它可能无所谓是否被执行...
finally
;_finalizer_指的是finalize()
方法。 - jaco0646