如下所示代码:
public class Example039 {
public static void main(String[] args) {
Example039 example039 = new Example039();
System.out.println(example039.output1());
example039.output2();
}
boolean output1() {
try {
// ...
return true;
} finally {
return false;
}
}
void output2() {
try {
System.out.println("执行try语句内容,然后exit,不正常退出");
System.exit(0);
} finally {
System.out.println("这里的finally没有执行,因为exit了");
}
}
}
输出结果:
false
执行try语句内容,然后exit,不正常退出
程序分析:
在一个 try-finally 语句中,finally 语句块总是在控制权离开 try 语句块时执行的。无论 try 语句块是正常结束的,还是意外结束的,情况都是如此。当 try 语句块和 finally 语句块都意外结束时,在 try 语句块中引发意外结束的原因将被丢弃,而整个 try-finally 语句意外结束的原因将于 finally 语句块意外结束的原因相同。在output1中,在 try 语句块中的 return 语句所引发的意外结束将被丢弃,而 try-finally 语句意外结束是由 finally 语句块中的 return 造成的。 简单地讲,程序尝试着(try)返回(return)true,但是它最终(finally)返回(return)的是 false。
每一个 finally 语句块都应该正常结束,除非抛出的是不受检查的异常。千万不要用一个 return、break、continue 或 throw 来退出一个 finally 语句块,并且千万不要允许将一个受检查的异常传播到一个 finally 语句块之外去。
根据以上分析,对于output1的输出是很容易理解的。但是output2却给了一个上述分析相反的例子。
不论 try 语句块的执行是正常地还是意外地结束,finally 语句块确实都会执行。然而output2程序中,try 语句块根本就没有结束其执行过程。System.exit 方法将停止当前线程和所有其他当场死亡的线程。finally 子句的出现并不能给予线程继续去执行的特殊权限。
当 System.exit 被调用时,虚拟机在关闭前要执行两项清理工作。 首先,它执行所有的关闭挂钩操作,这些挂钩已经注册到了 Runtime.addShutdownHook 上。这对于释放 VM 之外的资源将很有帮助。务必要为那些必须在 VM 退出之前发生的行为关闭挂钩。VM 执行在 System.exit 被调用时执行的第二个清理任务与终结器有关。
总之, System.exit 将立即停止所有的程序线程,它并不会使 finally 语句块得到调用,但是它在停止 VM 之前会执行关闭挂钩操作。当 VM 被关闭时,请使用关闭挂钩来终止外部资源。通过调用 System.halt 可以在不执行关闭挂钩的情况下停止 VM,但是这个方法很少使用。
注:本【java解惑】系列均是博主阅读《java解惑》原书后将原书上的讲解和例子部分改编然后写成博文进行发布的。所有例子均亲自测试通过并共享在github上。通过这些例子激励自己惠及他人。同时本系列所有博文会同步发布在博主个人微信公众号搜索“爱题猿”或者“ape_it”方便大家阅读。如果文中有任何侵犯原作者权利的内容请及时告知博主以便及时删除如果读者对文中的内容有异议或者问题欢迎通过博客留言或者微信公众号留言等方式共同探讨。
源代码地址https://github.com/rocwinger/java-disabuse
本文出自 “winger” 博客,谢绝转载!