187. Java 异常 - 什么是异常?
🚨 什么是“异常”?
在程序运行过程中,有些情况是“非正常的” —— 比如文件找不到、除数为零、数组越界……这些突发事件打断了程序原本的运行流程,这就是 异常(Exception)。
✅ 定义:
异常是程序运行时发生的、打断正常执行流程的一种事件。
当异常发生时:
- 当前方法会 创建一个异常对象,这个对象封装了错误信息;
- 然后将这个对象 抛给 Java 运行时系统;
- 运行时系统会寻找可以“处理”这个异常的代码块。
这个过程被称为:抛出异常(throwing an exception)。
🧱 异常对象中包含什么?
异常对象中通常包含以下信息:
- 异常的类型(如
NullPointerException、IOException等) - 错误发生时的程序状态(栈轨迹、具体位置等)
- 可选的错误消息(
message)
Java 是怎么“处理”异常的?
关键概念:调用栈(Call Stack)
可以想象程序运行是一个“方法接着方法调用”的过程。发生异常时,Java 会沿着调用栈往上“寻找处理者” 👇
main() → methodA() → methodB() → methodC() ← 异常发生在这里
Java 会从 methodC 开始,逐层往上查找,寻找能处理此异常的方法。
🧯 什么是异常处理器(Exception Handler)?
异常处理器是一段能够“捕获并处理”异常的代码块。通常使用 try-catch 语句编写:
try {
// 可能出错的代码
int result = 10 / 0;
} catch (ArithmeticException e) {
// 处理异常的代码
System.out.println("算术异常:除数不能为0!");
}
如果某个方法能处理该异常类型,它就 “捕获(catch)” 了这个异常,程序可以继续运行。
🧭 示例:调用栈中的异常传递过程
public class Demo {
public static void main(String[] args) {
methodA();
}
public static void methodA() {
methodB();
}
public static void methodB() {
methodC();
}
public static void methodC() {
int result = 10 / 0; // ArithmeticException
}
}
此代码运行时会报错:
Exception in thread "main" java.lang.ArithmeticException: / by zero
at Demo.methodC(Demo.java:14)
at Demo.methodB(Demo.java:10)
at Demo.methodA(Demo.java:6)
at Demo.main(Demo.java:2)
✅ Java 沿着调用栈找,但没有任何一个方法提供处理器,所以程序崩溃。
☠️ 如果没人处理异常会怎样?
如果异常从最底层冒到最顶层(main 方法),仍无人处理:
- 当前线程终止
- 如果是主线程 → 整个程序崩溃
💡 为什么使用异常比传统错误码更好?
传统方式(C 风格):
int status = doSomething();
if (status == -1) {
// 错误处理逻辑
}
Java 异常的优势在于:
| 特点 | 好处 |
|---|---|
| ❌ 非常规返回值 | ✔ 不影响主逻辑的返回 |
| ❌ 忽略容易 | ✔ 统一强制检查 |
| ❌ 错误信息不集中 | ✔ 异常对象封装信息 |
| ❌ 嵌套判断混乱 | ✔ try-catch 语义清晰 |
🔍 常见异常类型
| 异常类型 | 说明 |
|---|---|
NullPointerException | 访问 null 引用的方法或字段 |
ArrayIndexOutOfBoundsException | 数组越界 |
ArithmeticException | 除以零等算术错误 |
IOException | I/O 操作失败 |
ClassNotFoundException | 类未找到 |
🧾 小结
- 异常是运行时的问题,用对象表示,用抛出(
throw)来传播。 Java使用调用栈寻找可以处理异常的代码块。try-catch是处理异常的标准方式。- 异常使得错误处理逻辑与业务逻辑解耦,提升了代码清晰度。
🎯 建议实践
✅ 编写以下代码练习理解异常处理:
public class TestException {
public static void main(String[] args) {
try {
int[] arr = {1, 2, 3};
System.out.println(arr[3]); // 越界
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("数组越界了!");
e.printStackTrace(); // 查看异常轨迹
}
System.out.println("程序继续执行...");
}
}