- 1 1. 引言:为何在 Java 中 “try” 很重要
- 2 2. try 的基础:语法与工作原理
- 3 3. 如何使用 catch、finally、throw 和 throws
- 4 4. 高级模式:try-with-resources 与异常传播
- 5 异常传播:异常如何向上层方法移动
- 6 5. 常见错误、反模式及其修复方法
- 7 6. 实践代码示例:常用的异常处理模式
- 8 7. Java 版本差异与框架特定的异常处理
- 9 1. 各 Java 版本的异常处理演进
- 10 2. 受检异常 vs. 非受检异常(再探)
- 11 3. Spring(Spring Boot)中的异常处理
- 12 4. 在真实项目中如何思考异常设计
- 13 8. Summary: Using try Correctly Makes Java Code Far More Stable
- 14 ◆ 结束语
- 15 9. FAQ: Frequently Asked Questions About Java try and Exception Handling
- 15.1 Q1. Do try and catch always have to be written together?
- 15.2 Q2. What exception type should I specify in catch?
- 15.3 Q3. finally 必须总是使用吗?
- 15.4 Q4. 为什么要保持 try 块尽可能小?
- 15.5 Q5. 为什么“吞掉异常”很糟糕?
- 15.6 Q6. 我不明白 throw 和 throws 的区别。
- 15.7 Q7. 是否应该始终使用 try-with-resources?
- 15.8 Q8. 为什么 Spring Boot 很少使用 try/catch?
- 15.9 Q9. 异常越多越好吗?
- 15.10 Q10. 异常处理的一句话最佳实践是什么?
1. 引言:为何在 Java 中 “try” 很重要
在用 Java 编写程序时,你不可避免地会遇到 异常处理。文件读取、网络通信、数值计算、用户输入——程序随时可能遭遇意外错误。当这种 “异常” 发生时,如果没有任何防护措施,程序会立刻停止,进程会在半途中终止。
这时 Java 以 try 为核心的异常处理语法就派上用场了。
try 是一种对可能抛出错误的代码进行 “安全包装” 的机制,它是语言中极其重要的一环,支撑着 Java 的稳定行为。
try 语句的作用
- 防止程序因意外错误而停止运行
- 让你能够在异常情况下(记录日志、显示信息、释放资源等)进行恰当的控制
- 明确区分正常流程和错误流程
- 确保 “安全性” 与 “可靠性”,这在实际工作中至关重要
如此一来,try 就像一个 “安全装置”,为 Java 程序提供了稳固的保障。
刚开始可能会觉得有点抽象,但一旦弄懂了,它会显著提升代码质量。
本文适合的读者
- 刚开始学习 Java 的人
- 对如何正确编写 try/catch 仍有疑惑的人
- 想复习 try-with-resources 与异常传播机制的人
- 想在专业层面学习异常处理最佳实践的人
在本文中,我们将按部就班地讲解——从 try 的基础到高级模式、常见错误以及实用的处理方式,全部覆盖。
2. try 的基础:语法与工作原理
要理解异常处理,首先要掌握最基本的 try / catch 结构。Java 的异常处理设计旨在把 “可能抛出异常的代码” 与 “异常发生时要执行的代码” 明确分离。
基本的 try / catch 语法
Java 中最基础的异常处理语法如下所示:
try {
// Code that may throw an exception
} catch (Exception e) {
// Code to run when an exception occurs
}
如果在 try 块内部执行代码时抛出了异常,执行会立即中断,控制权转移到对应的 catch 块。相反,如果没有异常发生,catch 块则不会被执行,程序会继续向下执行后续代码。
基本执行流程
- 按顺序执行 try 块内部的代码
- 一旦出现异常,立即停止执行
- 跳转到匹配的 catch 块
- 执行 catch 块内部的代码
- catch 执行完毕后,继续执行 try/catch 之外的代码
这种流程可以防止在突发错误时整个程序崩溃。
面向初学者的示例:除以零
下面用一个通俗易懂的例子——“除以零”——来说明。
try {
int result = 10 / 0; // Division by zero → exception occurs
System.out.println("Result: " + result);
} catch (ArithmeticException e) {
System.out.println("Error: You cannot divide by zero.");
}
关键点
10 / 0会触发ArithmeticExceptiontry中剩余的语句(打印语句)不会被执行- 相反,
catch中的提示信息会被打印出来
通过这种方式,try 用来包装 “可能出错的部分”,并作为异常处理的入口点。
在 catch 中如何选择异常类型?
在 catch 的括号里,你必须指明想要捕获的异常 “类型”。
示例:
catch (IOException e)
catch (NumberFormatException e)
Java 有许多异常类,每一种都代表一种特定的错误。
作为初学者,使用 Exception 进行宽泛捕获是可以的,但在实际开发中,尽可能指定更具体的异常类型会更好,因为这能让根因分析和调试更加容易。
如果没有异常发生会怎样?
如果没有异常发生:
try块会执行到末尾catch块被跳过- 程序继续执行下一步处理
请记住,异常只会在“异常情况”下出现。
3. 如何使用 catch、finally、throw 和 throws
在 Java 异常处理里,try 语句会与多种结构一起使用。
每种结构的作用不同,正确使用它们可以让代码更易读、更安全。
下面我们将以初学者友好的方式解释 catch / finally / throw / throws。
catch:接收并处理异常的代码块
catch 是用于处理 try 中出现的异常的代码块。
try {
int num = Integer.parseInt("abc"); // NumberFormatException
} catch (NumberFormatException e) {
System.out.println("Cannot convert to a number.");
}
关键点
- 只处理
try内部抛出的异常 - 通过指定异常类型,可以仅对特定错误作出响应
- 可以放置多个
catch块,以不同方式处理不同的异常try { // Some processing } catch (IOException e) { // File-related error } catch (NumberFormatException e) { // Data format error }
finally:即使出现异常也一定会执行的代码
finally 块用于编写无论是否出现异常都必须执行的代码。
try {
FileReader fr = new FileReader("data.txt");
} catch (IOException e) {
System.out.println("Could not open the file.");
} finally {
System.out.println("Finishing processing.");
}
常见用法
- 关闭文件或网络连接
- 断开数据库连接
- 释放临时分配的资源
简而言之,当你想确保 清理工作一定会执行 时,就使用 finally。
throw:手动触发异常
throw 是一个关键字,用于显式触发异常。
public void checkAge(int age) {
if (age < 0) {
throw new IllegalArgumentException("Invalid age");
}
}
使用场景
- 当传入的参数无效时给出警告
- 根据业务逻辑应视为异常的情况
- 检测到“非法状态”时强制抛出异常
使用 throw,开发者可以有意将程序流程切换到异常路径。
throws:声明方法可能把异常传递给调用者
在方法签名中使用,表示:
“此方法可能抛出特定异常,调用者必须处理它。”
public void readFile() throws IOException {
FileReader fr = new FileReader("test.txt");
}
throws 的作用
- 方法内部不处理异常
- 将异常处理的责任委托给调用者
- 通过在方法签名中声明,使责任更加明确
在实际项目中,诸如
“我们在哪里捕获异常,在哪里向上层传播?”
的设计决策会对整体代码质量产生重大影响。
四者区别的汇总
| Keyword | Role |
|---|---|
| try | Wrap code that might throw an exception |
| catch | Catch and handle an exception that occurred |
| finally | Always executes regardless of whether an exception occurred |
| throw | Manually throw an exception |
| throws | Declare that a method may throw an exception |
理解了这些后,异常处理的整体图景会更加清晰。
4. 高级模式:try-with-resources 与异常传播
即使仅使用基本的 try / catch,Java 异常处理已经非常有用,但还有一些“高级模式”可以帮助你更安全、更高效地处理异常。在实际开发中,如何管理 资源清理 和 异常传播 对代码质量有着显著影响。
这里,我们将解释 try-with-resources(在 Java 7 中引入)以及 异常传播 的机制,即异常在方法边界之间的传递方式。
try-with-resources:自动关闭资源
许多操作——文件、套接字、数据库连接——都需要管理“资源”。
每当打开一个资源时,都必须在使用完后将其关闭。传统做法是手动在 finally 块中调用 close()。
然而,手动关闭很容易忘记,而且如果在使用过程中抛出异常,资源可能无法得到正确关闭。
这正是引入 try-with-resources 的原因。
try-with-resources 的基本语法
try (FileReader fr = new FileReader("data.txt")) {
// File operations
} catch (IOException e) {
System.out.println("Failed to read the file.");
}
在 try 的圆括号中声明的任何资源,都会 在是否抛出异常的情况下自动调用 close()。
使用 try-with-resources 的便利之处
- 不会忘记关闭资源
- 不需要在
finally中编写冗长的关闭逻辑 - 代码更简洁、更易读
- 即使
close()本身抛出异常,也能安全处理
在实际工作中,文件操作和数据库连接非常常见,因此 强烈建议在可能的情况下使用 try-with-resources。
同时处理多个资源
try (
FileReader fr = new FileReader("data.txt");
BufferedReader br = new BufferedReader(fr)
) {
String line = br.readLine();
System.out.println(line);
}
可以在括号中列出多个资源,所有资源都会自动关闭,这极其方便。
异常传播:异常如何向上层方法移动
另一个重要概念是“异常传播”。
当方法内部出现异常且没有在该位置使用 try / catch 进行处理时,异常会 原样传播给调用者。
异常传播的示例(throws)
public void loadConfig() throws IOException {
FileReader fr = new FileReader("config.txt");
}
调用该方法的代码必须处理该异常:
try {
loadConfig();
} catch (IOException e) {
System.out.println("Cannot read the configuration file.");
}
传播的好处
- 可以避免在底层方法中塞入过多错误处理逻辑,将责任交给更高层
- 方法结构更清晰,可读性提升
- 可以在统一位置集中记录和处理异常
需要注意的缺点
- 必须清楚异常最终会在何处被捕获
- 如果上层代码忘记处理,程序将会终止
- 过度使用
throws会使方法声明变得臃肿,使用起来更困难
在实际项目中,设计阶段需要决定:
“我们应该在哪里捕获异常,哪些地方应该向上层传播?”
try-with-resources 与异常传播的组合使用
public void readData() throws IOException {
try (BufferedReader br = new BufferedReader(new FileReader("data.txt"))) {
System.out.println(br.readLine());
}
}
- 资源自动关闭
- 异常自然传播给调用者
- 代码简短且更安全
这是一种非常实用的真实开发风格。
5. 常见错误、反模式及其修复方法
Java 的异常处理功能非常强大,但如果使用不当,会让代码难以阅读,甚至埋下 bug 的温床。
尤其是从初学者到中级开发者阶段,常会出现许多“反模式”(应当避免的模式),这些问题在生产环境中尤为突出。
下面,我们将说明几类典型错误并给出相应的改进建议。
1. try 块过大
try {
// A very long process, like 100 lines...
} catch (Exception e) {
// Handling when an exception occurs
}
问题
- 不清楚哪一行可能抛出异常
- 当出现 bug 时,定位原因变得非常困难
- 异常处理可能会作用于不需要处理的代码
解决方案
- 只包装实际可能抛出异常的代码块
- 将业务逻辑与异常处理明确分离
// Pre-processing try { loadConfig(); // Only this part can throw an exception } catch (IOException e) { // Error handling } // Post-processing
2. 捕获空的 catch(吞掉异常)
try {
int n = Integer.parseInt(input);
} catch (NumberFormatException e) {
// Do nothing (silently ignore)
}
这是最糟糕的反模式之一。
问题
- 你根本不知道错误已经发生
- Bug 无法被发现,调试变得不可能
- 在真实项目中,这可能直接导致严重事故
解决方案
- 始终记录日志或向用户展示错误信息
- 最后手段可以重新抛出异常
catch (NumberFormatException e) { System.err.println("Invalid input: " + e.getMessage()); }
3. 使用过于宽泛的异常类型进行捕获
catch (Exception e) {
// Catch everything
}
问题
- 难以确定实际发生了什么
- 可能会意外处理本不该处理的异常
- 重要错误可能被隐藏
解决方案
- 尽可能指定更具体的异常类型
- 如果确实需要对异常进行分组,使用 “多捕获”(multi‑catch)
catch (IOException | NumberFormatException e) { // Handle multiple exceptions together }
4. 在 finally 中抛出异常
finally {
throw new RuntimeException("Exception thrown in finally");
}
问题
- 来自 try/catch 的“原始异常”可能会丢失
- 堆栈跟踪变得混乱,调试困难
- 在真实项目中,这会使根本原因的调查几乎不可能
解决方案
- 在 finally 中仅编写清理代码
- 不要加入会抛出异常的逻辑
5. 忘记调用 close()
这在传统的 try/finally 方式中经常出现。
FileReader fr = new FileReader("data.txt");
// Forgot to call close() → memory leaks, file locks remain
解决方案:使用 try‑with‑resources
try (FileReader fr = new FileReader("data.txt")) {
// Safe auto-close
}
当需要资源管理时,通常应将 try‑with‑resources 视为默认标准。

6. 认为“我应该把所有异常都用 throws 抛出”
public void execute() throws Exception {
// Delegate everything to throws
}
问题
- 调用方被迫处理大量异常,设计会崩溃
- 谁负责处理错误变得不明确
解决方案
- 只在低层方法中捕获应当处理的异常
- 只向上层传播关键异常(保持平衡)
防止反模式的核心原则
- 将 try 块保持尽可能小
- 在 catch 中使用具体的异常类型
- finally 只用于清理工作
- 切勿编写空的 catch 块
- 使用 try‑with‑resources 统一资源处理
- 设计异常时考虑“责任”归属
- 始终记录日志
仅遵循这些原则就能显著提升代码质量。
6. 实践代码示例:常用的异常处理模式
在本节中,我们介绍在实际 Java 开发中常用的异常处理模式,并提供具体代码示例。我们不仅停留在语法解释,而是提供可直接在真实项目中使用的示例。
1. 文件读取的异常处理(try‑with‑resources)
最常见的情况之一是文件操作的异常处理。
由于文件访问很容易失败,异常处理是必不可少的。
try (BufferedReader br = new BufferedReader(new FileReader("data.txt"))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
System.out.println("An error occurred while reading the file: " + e.getMessage());
}
关键点
- try-with-resources 消除了显式
close()的需求 - 捕获
IOException是标准做法 - 在失败时记录原因可以让调查更容易
2. 验证用户输入并处理异常
用户输入是常见的 bug 来源。
无效的输入值通常被视为异常。
public int parseAge(String input) {
try {
int age = Integer.parseInt(input);
if (age < 0) {
throw new IllegalArgumentException("Age must be zero or greater");
}
return age;
} catch (NumberFormatException e) {
throw new NumberFormatException("Please enter a numeric value");
}
}
常见的实际用例
- 输入验证
- 控制错误信息
- 使用
throw有意将逻辑错误转换为异常
3. 使用多个 catch 块对异常进行分类
当单个过程可能出现多种异常时,
你可以准备多个 catch 块来区分错误类型。
try {
processTask();
} catch (IOException e) {
System.out.println("I/O error: " + e.getMessage());
} catch (NullPointerException e) {
System.out.println("An unexpected null value was detected");
} catch (Exception e) {
System.out.println("An unexpected error occurred");
}
好处
- 更容易识别错误原因
- 允许分支到相应的处理逻辑
4. 记录异常并重新抛出(在实践中非常常见)
在实际系统中,通常会记录异常然后将其重新抛给调用者。
try {
processData();
} catch (IOException e) {
System.err.println("Log: An I/O error occurred during data processing");
throw e; // Propagate the exception to the caller
}
为什么这样实用
- 日志使调查更容易
- 异常处理责任可以委派给更高层
5. API 调用和服务通信的异常处理
与外部 API 或服务通信的代码容易出现故障。
try {
String response = httpClient.get("https://example.com/api");
System.out.println("Response: " + response);
} catch (IOException e) {
System.out.println("A communication error occurred. Please try again.");
}
需要注意的事项
- 网络通信极易产生异常
- 可能需要重试逻辑
- 基于 HTTP 状态的错误通常应单独处理
6. 定义自定义异常类(高级模式)
随着项目规模扩大,你可能需要定义特定于应用的异常。
public class InvalidUserException extends Exception {
public InvalidUserException(String message) {
super(message);
}
}
public void validateUser(User user) throws InvalidUserException {
if (user == null) {
throw new InvalidUserException("Invalid user data");
}
}
好处
- 自定义错误类型以匹配项目领域
- 设计与业务逻辑相匹配的异常结构
实际项目中的异常处理最佳实践
- 尽可能保持
try块小 - 尽可能使用
try-with-resources - 在
catch中指定具体的异常类型 - 绝不要写空的
catch块 - 在适当时记录异常并重新抛出
- 明确界定异常处理的责任
遵循这些原则可在实际项目中实现稳定、可维护的代码。
7. Java 版本差异与框架特定的异常处理
Java 的异常处理机制已经存在很久,但每个版本都加入了新特性,扩展了其使用方式。此外,实际项目中常用的框架——例如 Spring——通常有自己的异常处理理念,与纯 Java 不同。
在本节中,我们将逐版本说明 Java 的变化,并介绍主要框架中异常处理的做法。
1. 各 Java 版本的异常处理演进
Java 7:引入 try-with-resources(革命性变化)
在 Java 7 之前,资源的清理必须写在 finally 块中。
FileReader fr = null;
try {
fr = new FileReader("data.txt");
} finally {
if (fr != null) fr.close();
}
问题
- 代码冗长
close()也可能抛出异常,需要嵌套的 try/catch- 容易引入资源泄漏
Java 7 通过 try-with-resources 解决
try (FileReader fr = new FileReader("data.txt")) {
// Read data
}
- 自动调用
close() - 不需要 finally
- 简单且安全
→ 这是实际 Java 开发中最重要的更新之一。
Java 8:错误处理与 Lambda 表达式相结合
Java 8 引入了 Lambda 表达式,使得在流式处理内部进行异常处理变得更常见。
List<String> list = Files.lines(Paths.get("test.txt"))
.collect(Collectors.toList());
当在流中出现 IOException 时,受检异常变得难以处理。
因此,常见的做法是 将受检异常包装成 RuntimeException。
Java 9 及以后:对 try-with-resources 的增强
在 Java 9 中,已经声明的变量可以直接传入 try-with-resources。
BufferedReader br = new BufferedReader(new FileReader("data.txt"));
try (br) {
System.out.println(br.readLine());
}
好处
- 可以提前创建资源,再将其加入 try-with-resources
- 灵活性提升
2. 受检异常 vs. 非受检异常(再探)
Java 异常分为两大类。
受检异常
IOExceptionSQLExceptionClassNotFoundException
→ 必须在方法签名中使用 throws 声明或显式捕获。
非受检异常
NullPointerExceptionIllegalArgumentExceptionArithmeticException
→ 不需要 throws 声明。
→ 运行时抛出。
在实践中,一个常用的经验法则是:
可恢复的业务错误 → 受检异常
编程缺陷 → 非受检异常
3. Spring(Spring Boot)中的异常处理
在 Spring / Spring Boot 这类最常用的 Java 框架中,异常处理的设计略有不同。
Spring 方式的特征
- 异常通常统一为
RuntimeException(非受检) - 异常在 DAO、Service、Controller 层之间分层传递
- 使用
@ExceptionHandler与@ControllerAdvice实现集中处理
示例:Controller 层的异常处理
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleException(Exception e) {
return ResponseEntity.status(500).body("A server error occurred");
}
}
好处
- 将异常处理集中在一个位置
- 消除 Controller 中不必要的 try/catch 块
- 适合大规模服务的开发
4. 在真实项目中如何思考异常设计
- 在底层处理业务可恢复的异常
- 将不可处理的异常向上抛出,并在 Controller 层进行处理
- 对外部 API、数据库访问等高风险操作记录详细日志
- 在项目中统一异常类型
- 识别哪些异常是可恢复的(例如重试)
与其只关注 Java 语法,
设计整体应用行为 才是真正重要的。
8. Summary: Using try Correctly Makes Java Code Far More Stable
在本文中,我们围绕 try 语句 介绍了 Java 的异常处理,从基础到实用用法、反模式,甚至版本差异。异常处理对初学者来说常常感觉困难,但只要正确理解,它就会成为显著提升代码质量的强大工具。
让我们回顾关键要点。
◆ 理解 try 语句的作用
- 用于安全地包装可能抛出异常的代码
- 防止程序异常终止,提升稳定性
- 明确区分正常流程与错误流程
异常处理的第一步是了解 try/catch 的工作原理。
◆ 正确使用 catch、finally、throw 与 throws
- catch:捕获并处理异常
- finally:编写必须始终执行的清理代码
- throw:主动抛出异常
- throws:将异常处理委托给调用者
弄清这些角色的区别会让异常处理设计变得更容易。
◆ try-with-resources 在实践中必不可少
Java 7 引入的该语法带来了重大好处:
“安全且自动关闭资源。”
对于处理文件、网络或数据库的代码,
在现代 Java 开发中,使用 try-with-resources 作为标准做法已成常规。
◆ 避免常见错误可显著提升质量
- 让 try 块过大
- catch 块留空
- 过度使用 Exception 捕获所有异常
- 在 finally 中抛出异常
- 忘记关闭资源
这些是初学者和中级开发者常犯的陷阱。仅仅避免它们,就能让代码明显更好。
◆ 在真实项目中决定异常处理位置至关重要
- 应在底层处理的异常
- 应向上层传播的异常
- 在 Spring 等框架中进行集中处理
异常处理不仅影响代码质量,还影响
整体应用架构。
◆ 结束语
try 语句是 Java 异常处理的基础,但它同样
深刻影响代码的稳定性、可读性和可维护性。
即使起初感觉困难,关注以下方面也会帮助你逐步深入理解:
- 异常的工作原理
- 如何使用 try-with-resources
- 保持 try 块简洁
- 设计合适的 catch 块
在实际开发中,
决定“在哪里处理异常” 并保持一致的异常设计,能够构建出健壮的应用程序。
希望本文能帮助你理解 Java 的 try 语句和异常处理,并支持你编写稳定、可靠的代码。
9. FAQ: Frequently Asked Questions About Java try and Exception Handling
Q1. Do try and catch always have to be written together?
A. In most cases, yes. However, there are valid exceptions such as try-with-resources combined with finally.
In standard syntax,
try { ... } catch (...) { ... }
is typically used as a pair.
However, the following combinations are also valid:
try + finallytry-with-resources + catchtry-with-resources + finally
Q2. What exception type should I specify in catch?
A. As a rule, specify the concrete exception type that can actually occur in that process.
Examples:
- 文件操作 →
IOException - 数值转换 →
NumberFormatException - 数组访问 →
ArrayIndexOutOfBoundsException
捕获所有 Exception 看似方便,
但实际上会让人难以了解到底发生了什么,应该避免这样做。
Q3. finally 必须总是使用吗?
A. 不需要。只有在必须始终执行的清理代码时才使用。
自 Java 7 起,
- 文件
- 套接字
- 数据库连接
通常使用 try-with-resources 处理,许多情况下已经不再需要 finally。
Q4. 为什么要保持 try 块尽可能小?
A. 因为这样更容易定位异常发生的位置。
如果 try 块过大:
- 无法判断错误具体出在哪儿
- 正常代码被不必要地卷入异常处理
- 调试变得困难
Q5. 为什么“吞掉异常”很糟糕?
A. 因为错误被隐藏,根本原因可能永远找不到。
示例:
catch (Exception e) {
// Do nothing ← NG
}
这是实际开发中最令人反感的模式之一。
至少要记录错误或显示相应的提示信息。
Q6. 我不明白 throw 和 throws 的区别。
A. throw 表示“实际抛出异常”,而 throws 表示“声明可能会抛出异常”。
throw:主动抛出异常throws:声明可能会抛出异常
示例:
throw new IllegalArgumentException(); // Throw here
public void load() throws IOException {} // Declare possibility
Q7. 是否应该始终使用 try-with-resources?
A. 在需要资源管理时几乎是强制性的。
- 自动 close()
- 不再需要 finally
- 代码简洁
- 即使出现异常也安全
在现代 Java 开发中,try-with-resources 已被视为标准做法。
Q8. 为什么 Spring Boot 很少使用 try/catch?
A. 因为 Spring 提供了集中式异常处理机制,如 @ExceptionHandler 和 @ControllerAdvice。
这使得:
- 在 Controller 层捕获异常
- 统一错误响应
- 业务逻辑保持专注且简洁
Q9. 异常越多越好吗?
A. 不是。抛出过多异常会让代码难以阅读。
关键要点:
- 处理业务可恢复的异常
- 将编程缺陷视为 RuntimeException
- 明确划分异常处理的职责
Q10. 异常处理的一句话最佳实践是什么?
A. “保持 try 块小,捕获具体异常,仅在需要时使用 finally,并自动关闭资源。”
仅遵循这一原则,就能显著提升异常处理的质量。
