程序员圈子里流传着一句话:“finally是代码的保险柜,永远会执行”。但真相是——这个"保险柜"的钥匙,有时候会被偷偷藏起来。
举个:你点了外卖,外卖小哥说"一定送到",但如果他半路摔跤骨折了呢?同理,finally块虽然设计初衷是"无论如何都要执行",但某些极端场景下,它也会"罢工"。今天我们就来扒一扒那些让finally失效的"黑手党"。

先别慌!在99%的情况下,finally确实是可靠的:
try块正常执行完:比如你读取文件后,finally里的file.close()会确保释放资源。try中抛出异常:即使程序崩溃,finally也会在崩溃前"托孤",完成收尾工作。try里有return:哪怕你提前返回,finally也会在return前抢着执行(像极了老妈在你出门前硬塞水果)。public static int testFinally() { try { return 1; } finally { System.out.println("就算有return,我也要执行!"); // 输出这句话 } } 五大"黑手党":让finally失效的元凶1. 代码根本没进try块(纯路人模式)场景:try块前直接return或报错。后果:finally连出场机会都没有。
public static void main(String[] args) { if (true) return; // 直接退出 try { // 永远执行不到的代码 } finally { System.out.println("你看不到我"); // 不会执行! } }教训:别把关键逻辑写在try块外。
2. System.exit(0):终极"杀手锏"场景:在try里调用System.exit()强制关闭JVM。后果:程序原地蒸发,finally直接消失。
try { System.out.println("准备跑路..."); System.exit(0); // 强制退出 } finally { System.out.println("求求让我执行一次"); // 不会执行! }忠告:慎用System.exit(),尤其别在try里用。
3. 死循环/死锁:卡到天荒地老场景:try块陷入无限循环或线程死锁。后果:代码卡死,finally永远等不到执行时机。
try { while (true) { // 无限转圈圈... } } finally { System.out.println("等到海枯石烂"); // 不会执行! }对策:用超时机制或监控线程避免死锁。
4. JVM崩溃:毁灭性打击场景:JVM因内存溢出、系统断电等崩溃。后果:整个程序灰飞烟灭,finally彻底凉凉。真相:这不是代码问题,而是物理世界的降维打击。
5. 守护线程的"无情抛弃"冷知识:如果非守护线程已结束,即使守护线程的try未完成,JVM也会直接退出,finally可能来不及执行。
如何用好finally?关键资源别依赖finally:数据库连接、文件句柄等建议用try-with-resources(Java 7+)。避免在finally里写return:会覆盖try中的返回值,引发诡异BUG。System.exit()是秘密武器:除非必要,否则用return或异常替代。没有绝对的安全,只有周全的设计finally就像程序员的备胎计划——虽然大多数时候靠谱,但永远要留个后手。牢记 :代码的可靠性不靠单点保障,而是层层防御。下次面试官再问这个问题,你可以邪魅一笑:“它很努力,但世界太残酷啊!”