193. Java 异常 - Java 异常处理之 Catch 块详解
✅ 什么是 catch 块?
我们已经知道 try 块用来“尝试”执行可能出错的代码。那么,如果真的出错了,程序是如何应对的?
这就要靠 catch 块了!
try {
// 可能出异常的代码
} catch (异常类型 变量名) {
// 处理该类型异常的代码
}
catch是异常处理器(Exception Handler)- 它负责“接住”抛出来的异常对象
- 每个
catch块只能处理一种异常类型(除非你合并异常,我们稍后讲)
✍️ 示例:writeList() 方法的两个异常处理器
我们来看两个经典的异常处理写法,分别处理:
IndexOutOfBoundsException(未受检)IOException(受检)
try {
// 可能抛出异常的操作
} catch (IndexOutOfBoundsException e) {
System.err.println("索引越界异常:" + e.getMessage());
} catch (IOException e) {
System.err.println("IO异常捕获:" + e.getMessage());
}
📌 注意:
- JVM 从上往下检查
catch,第一个匹配的就被调用 - 如果你写错了顺序,比如先捕获父类,再捕获子类,编译器直接报错!
🚫 错误示例:父类异常写在前,子类异常写在后
来看这个错误写法:
try {
// some IO code
} catch (IOException ioe) {
// 父类异常处理
} catch (FileNotFoundException fnfe) {
// 子类异常处理(永远执行不到)
}
💥 错误原因:
FileNotFoundException是IOException的子类- 所以前面的
IOException已经把后者包括了,后者永远不会被执行 - 编译器会提示:“
FileNotFoundException已经被上面的 catch 捕获”
✅ 正确顺序应该是:先写子类,再写父类!
🧠 catch 块内部做什么?
虽然很多初学者的 catch 只是打印错误信息,但其实它能做的更多:
| 用途 | 示例说明 |
|---|---|
| ✅ 打印日志 | System.err.println(...) |
| 🔁 重试机制 | 比如提示用户重新输入 |
| 🧼 资源清理 | 如果没有 finally,你也可以在 catch 中关闭文件或数据库连接 |
| 🚀 异常链传递 | 把异常封装后继续向上传递(后面讲 chained exception) |
- “catch 就像安全网,专门接你 try 跳伞失败之后的落地。”
- “每个 catch 都是一个守门员,只接自己看得懂的球。”
- “别写错顺序——父类先出场,子类就被‘抢戏’了!”
🎓 小结梳理:
| 项目 | 要点 |
|---|---|
| 写法 | catch (异常类型 变量名) |
| 顺序 | 子类在前,父类在后 |
| 匹配机制 | 异常类型兼容或等于 catch 中声明的类型即可匹配 |
| 行为 | 打印、恢复、传递、终止程序都可以在 catch 中进行 |