当前位置: 首页 > news >正文

Java高效编程(9):优先使用 try-with-resources 而非 try-finally**

解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界

在Java编程中,许多资源(如 InputStreamOutputStreamjava.sql.Connection)必须在使用后手动关闭。然而,开发者常常忘记关闭这些资源,导致严重的性能问题。虽然终结器(详见【条目8】)曾经被用作安全网,但它们并不可靠。在 Java 7 之前,try-finally 语句是确保资源正确关闭的唯一方式,即使在异常或提前返回时,try-finally 也能保证资源关闭:

// 使用 try-finally 关闭资源 - 不再是最佳方式
static String firstLineOfFile(String path) throws IOException {BufferedReader br = new BufferedReader(new FileReader(path));try {return br.readLine();} finally {br.close();}
}

虽然这种方式看起来并不坏,但在处理多个资源时,它会变得非常繁琐:

// 使用 try-finally 处理多个资源时代码显得复杂
static void copy(String src, String dst) throws IOException {InputStream in = new FileInputStream(src);try {OutputStream out = new FileOutputStream(dst);try {byte[] buf = new byte[BUFFER_SIZE];int n;while ((n = in.read(buf)) >= 0) {out.write(buf, 0, n);}} finally {out.close();}} finally {in.close();}
}

即使是优秀的程序员,也经常在 try-finally 中犯错。事实上,Java 库中有三分之二的 close 方法调用在2007年是错误的。

使用 try-finally 的问题

即使 try-finally 可以正确关闭资源,但它存在一个微妙的问题:try 块和 finally 块中的代码都可能抛出异常。例如,在 firstLineOfFile 方法中,readLine 方法可能由于设备故障抛出异常,而 close 方法也可能因此失败。在这种情况下,后续的异常会掩盖第一个异常,导致调试变得非常困难。虽然可以编写代码来抑制第二个异常,但几乎没有人会这么做,因为代码会变得冗长复杂。

Java 7 的解决方案:try-with-resources

Java 7 引入了 try-with-resources 语句,解决了 try-finally 的所有问题。要使用该语句,资源类必须实现 AutoCloseable 接口,该接口只有一个返回 voidclose 方法。Java 库和第三方库中的许多类现在都实现了该接口。以下是使用 try-with-resources 重写的 firstLineOfFile 方法:

// 使用 try-with-resources - 最佳资源关闭方式
static String firstLineOfFile(String path) throws IOException {try (BufferedReader br = new BufferedReader(new FileReader(path))) {return br.readLine();}
}

try-with-resources 同时处理多个资源时,代码更加简洁:

// 使用 try-with-resources 处理多个资源 - 简洁明了
static void copy(String src, String dst) throws IOException {try (InputStream in = new FileInputStream(src);OutputStream out = new FileOutputStream(dst)) {byte[] buf = new byte[BUFFER_SIZE];int n;while ((n = in.read(buf)) >= 0) {out.write(buf, 0, n);}}
}

try-with-resources 的优势

try-finally 相比,try-with-resources 更加简洁且易于维护。它不仅减少了冗余的代码,还提供了更好的异常处理机制。如果在 try 块和 close 方法中同时抛出异常,try-with-resources 会抑制后续异常,并保留最重要的第一个异常。抑制的异常不会被简单忽略,而是记录在异常堆栈中,并带有“抑制异常”的说明。你可以通过 Throwable.getSuppressed 方法程序化地访问这些抑制的异常。

你也可以像在普通 try-finally 中一样,为 try-with-resources 添加 catch 子句来处理异常。如下所示是一个不抛出异常的 firstLineOfFile 版本,它在无法打开文件时返回默认值:

// 带有 catch 子句的 try-with-resources
static String firstLineOfFile(String path, String defaultVal) {try (BufferedReader br = new BufferedReader(new FileReader(path))) {return br.readLine();} catch (IOException e) {return defaultVal;}
}

通过这种方式,你可以优雅地处理异常,而无需增加代码的嵌套层次。

总结

try-with-resources 是关闭资源的最佳方式。它不仅代码简洁、清晰,而且能够正确处理多个异常,确保抛出的异常是最有用的,抑制的异常也不会丢失。与 try-finally 相比,try-with-resources 的优势明显,强烈建议在需要关闭资源的场景下使用这一语句。


http://www.mrgr.cn/news/41039.html

相关文章:

  • QT系统学习篇(3)- Qt开发常用算法及控件原理
  • 综合实验二 利用智能小车探测环境
  • Microsoft 更新 Copilot AI,未來將能使用語音並看到你瀏覽的網頁
  • HISTCITE分析进阶
  • 水凝胶应用受限,3D打印助力,多材融合创新
  • 带徒实训项目ApiFirst实战讲义:导出文档支持API分组校验
  • 【递归】10. leetcode 111 二叉树的最小深度
  • Flink从ck拉起任务脚本
  • Visual Studio C# 处理和修复 WinRiver II 测量项目 MMT 文件错误
  • C++ 语言特性08 - 非静态成员的初始化
  • 音视频入门基础:FLV专题(10)——Script Tag实例分析
  • Leecode热题100-48.旋转图像
  • 【MAUI】CollectionView之 垂直网格
  • html中的文本标签(含标签的实现案例)
  • .NET 一款支持冰蝎的免杀WebShell
  • 麒麟系统命令失效快速修复
  • 一文掌握Harbor镜像同步公有云镜像仓库实践
  • Python机器学习框架介绍和入门案例:Scikit-learn、TensorFlow与Keras、PyTorch
  • JS中Object和Array的相互转换:深入全面讲解
  • 语言的嵌套和函数指针