finally代码块不被执行的情况总结
以前跟别人讨论finally关键字,我总是简单的说:“fianly代码块中的代码一定会执行,一般用来清除IO资源等非内存资源(内存资源由GC机制回收)”。 今天翻书发现了几种不会执行的情况,现在总结下。
1.finally的含义
finally的真正含义是指从try代码块出来才一定会执行相应的finally代码块。
public class Test { public static void main(String[] args) { foo(false); } public static void foo(boolean flag) { System.out.println("enter foo()"); if(flag) { try { System.out.println("enter try block"); } finally { System.out.println("enter finally block"); } } else { System.out.println("leave foo()"); } } } /****************** 控制台打印如下 enter foo() leave foo() *******************/
上述代码,flag为false,没有进入try代码块,对应的finally自然也不会执行。
2.System.exit()
System.exit()的作用是中止当前虚拟机,虚拟机都被中止了,finally代码块自然不会执行。
public class Test { public static void main(String[] args) { foo(); } public static void foo() { System.out.println("enter foo()"); try { System.out.println("enter try block"); System.exit(); } finally { System.out.println("enter finally block"); } } } /***************** 控制台打印如下 enter foo() enter try block ******************/
上述代码,进入foo()方法后再进入try代码块,但是在进入finally代码块之前调用了System.exit()中止虚拟机, finally代码块不会被执行。
3.守护(daemon)线程被中止时
java线程分为两类,守护线程和非守护线程。当所有的非守护线程中止时,不论存不存在守护线程,虚拟机都会kill掉守护线程从而中止程序。 虚拟机中,执行main方法的线程就是一个非守护线程,垃圾回收则是另一个守护线程,main执行完,程序就中止了,而不管垃圾回收线程是否中止。 所以,如果守护线程中存在finally代码块,那么当所有的非守护线程中止时,守护线程被kill掉,其finally代码块是不会执行的。
public class Test { public static void main(String[] args) { Thread t = new Thread(new Task()); t.setDaemon(true); //置为守护线程 t.start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { throw new RuntimeException("the "+Thread.currentThread().getName()+" has been interrupted",e); } } } class Task implements Runnable { @Override public void run() { System.out.println("enter run()"); try { System.out.println("enter try block"); TimeUnit.SECONDS.sleep(5); //阻塞5s } catch(InterruptedException e) { System.out.println("enter catch block"); throw new RuntimeException("the "+Thread.currentThread().getName()+" has been interrupted",e); } finally { System.out.println("enter finally block"); } } } /******************* 控制台打印如下 enter run() enter try block ********************/
上述代码,main()执行完,非守护线程也就结束了,虽然线程t处于阻塞状态,但由于其是守护线程,所以程序仍会中止。 而且,即使其进入了try代码块,finally代码块也不会被执行。
总结
finally代码块并非一定执行,在不进入try代码块或者程序被中止时就不会执行。
引用
1.《Java编程思想》
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人