一句话说透Java里面的finally-return

112 阅读2分钟

一句话总结:
finally 里的 return 像霸道总裁——不管 try/catch 怎么折腾,最终都得听我的!


一、基础规则:finally 必执行

  • 无论 try/catch 里是否报错、是否有 return,finally 代码块必定执行(除非 JVM 崩溃)。
  • 常见用途:关闭文件、释放数据库连接等清理操作。
public int demo() {  
    try {  
        System.out.println("try 执行");  
        return 1;  
    } catch (Exception e) {  
        return 2;  
    } finally {  
        System.out.println("finally 执行");  
    }  
}  
// 输出:  
// try 执行  
// finally 执行  
// 返回值:1  

二、finally 里写 return 会怎样?

场景 1:finally 无 return

  • try/catch 的 return 暂存结果,等 finally 执行完再返回。
  • 值类型:返回的是 try/catch 中暂存的原始值(finally 里修改无效!)。
  • 引用类型:修改对象属性会影响结果(因为引用地址不变)。
public int demo() {  
    int num = 0;  
    try {  
        num = 1;  
        return num; // 暂存 num=1  
    } finally {  
        num = 2; // 修改无效!最终返回 1  
    }  
}  

场景 2:finally 有 return

  • 直接覆盖 try/catch 的返回值,且会吞掉异常(极其危险!)。
public int demo() {  
    try {  
        throw new RuntimeException("报错啦!");  
    } catch (Exception e) {  
        System.out.println("捕获异常");  
        return 1;  
    } finally {  
        return 666; // 最终返回 666,异常被吞!  
    }  
}  
// 输出:捕获异常  
// 返回值:666(异常消失!)  

三、为什么 finally return 会吞异常?

  • JVM 执行逻辑

    1. try 里抛异常 → catch 处理 → 准备返回 1。
    2. 执行 finally → 遇到 return 666 → 直接覆盖返回值,并结束方法。
    3. 原本要抛的异常被丢弃,像从未发生过!

四、血泪教训:千万别在 finally 里写 return!

  • 坑点总结

    1. 覆盖返回值:导致预期外的结果。
    2. 吞掉异常:错误被隐藏,极难调试!
    3. 代码反直觉:其他开发者容易踩坑。

五、正确姿势:finally 只做清理,别 return!

public void readFile() {  
    FileInputStream fis = null;  
    try {  
        fis = new FileInputStream("test.txt");  
        // 读文件...  
    } catch (IOException e) {  
        e.printStackTrace();  
    } finally {  
        if (fis != null) {  
            try {  
                fis.close(); // 只做清理!  
            } catch (IOException e) {  
                e.printStackTrace();  
            }  
        }  
    }  
}  

总结口诀:

“try/catch 可 return,finally 必执行。
若在 finally 写 return,返回值被覆盖,异常全失踪!”