finally 的作用
finally 是 Java 异常处理机制的组成部分,它保证了代码块中的代码一定要被执行。通常我们会将资源释放的代码写在 finally 代码块中,如 I/O 的关闭、数据库连接的关闭等。
但是也会存在 finally 代码块中的代码不会执行的情况,本文就是总结了这些情况。
finally 代码块不会执行的情况
之前在网上的帖子看到有一种情况是叫做”不进入 try 代码块“,这不废话吗,不进入 try 当然不会执行 finally 代码块。所以本文讨论的是进入 try 代码块后 finally 代码块不执行的情况。
1. 虚拟机被终止 System.exit();
System.exit(0)
的作用是中止当前正在运行的 Java 虚拟机。如果虚拟机被中止,程序也会被终止,所以在它后面的代码都不会被执行,即便是 finally 代码块也同样不会执行。
private static void demo1() {
try {System.out.println("执行 try 代码块");
System.exit(0);
} finally {System.out.println("开始执行 finally 代码块");
}
}
/** 控制台输出:执行 try 代码块
**/
2. try 代码块无限循环
这是由于业务逻辑的原因,一直在执行 try 代码块的业务并且永远无法终止,try 代码块都没执行完,自然无法执行 finally 代码块。
private static void demo2() {
try {while (true) {
// do something
System.out.println("执行 try 代码块");
}
} finally {System.out.println("开始执行 finally 代码块");
}
}
/** 控制台输出:执行 try 代码块
执行 try 代码块
...(一直输出)**/
3. 在被中止的守护线程内
Java 中的线程可以分为守护线程和用户线程。当程序中所有的用户线程都终止时,虚拟机会 kill 所有的守护线程来终止程序。
当 try-finally 代码块存在于守护线程,而此守护线程因用户线程被销毁而终止时,该守护线程不会继续执行。
假设用户线程(main 线程)执行完毕后,作为守护线程的 thread 对象中的 try 代码块还没有执行结束,当用户线程执行结束后,此时已不存在用户线程,虚拟机会强制中止守护线程 thread,导致 finally 代码块不会被执行。
private static void demo3() {Thread thread = new Thread(() -> {
try {System.out.println("执行 try 代码块,等待 2s,等待主线程执行结束...");
Thread.sleep(2000);
} catch (InterruptedException e) {e.printStackTrace();
} finally {System.out.println("开始执行 finally 代码块");
}
});
thread.setDaemon(true);
thread.start();}
/** 控制台输出:执行 try 代码块,等待 2s,等待主线程执行结束...
**/
参考博客
finally 块不被执行的情况总结