finally的核心价值是确保关键清理动作无条件执行,需提前声明资源变量、判空并捕获close异常,优先使用try-with-resources,且finally仅用于资源释放。

finally 的核心价值不是“兜底执行”,而是确保关键清理动作无条件发生——哪怕 try 抛异常、catch 里 return,甚至 catch 再抛新异常,它依然会运行。
资源变量必须提前声明
如果把文件流、临时文件对象等在 try 块内 new 出来,一旦构造过程出错(比如路径非法、磁盘满),变量根本没被初始化,finally 就无法访问它。正确做法是:在 try 外声明为 null,再在 try 内赋值。
- 声明写在 try 前:
FileInputStream fis = null;或File tempFile = null; - 避免在 try 内直接声明并初始化,否则 finally 会报编译错误或空指针
- 对临时文件,推荐用
Path tempPath = Files.createTempFile(...),再传给 finally 处理
finally 中关闭资源要加判空和异常捕获
close() 方法本身可能失败(如网络中断、权限不足),若不处理,反而会在 finally 里抛出新异常,掩盖原始错误。
- 先判断资源是否非 null,再调用 close()
- close() 要套一层 try-catch,异常可记录日志或忽略,但不能向上抛
- 不要写
fis.close();这种裸调用,也不要用throw e;替代throw;,以免破坏堆栈追踪
优先用 try-with-resources 替代手动 finally
Java 7+ 提供的 try-with-resources 是更安全、简洁的替代方案,适用于实现了 AutoCloseable 的资源(如 InputStream、Connection、Scanner)。
- 资源在 try 括号内声明,自动在退出时调用 close()
- 即使 try 中抛异常,close() 仍会执行;多个资源按逆序关闭
- 若 close() 抛异常,会被“压制”(suppressed),主异常仍保留,可通过
getSuppressed()查看
finally 不是日志打印区,更不是逻辑兜底处
它的职责非常单一:释放资源。其他事情不该塞进来。
- 别在 finally 里写业务逻辑、重试、降级或发通知——这些该放在 catch 里
- 避免在 finally 中 return 或 throw,否则会覆盖 try/catch 的返回值或异常
- 临时文件删除建议用
Files.deleteIfExists(path),比File.delete()更健壮,失败时抛明确异常便于排查


















