203. Java 异常 - Throwable 类及其子类
概述
在 Java 中,所有可被抛出的异常和错误都继承自 java.lang.Throwable
。Throwable
有两个直接子类:
Error
:表示严重的、通常无法恢复的错误(如虚拟机崩溃、内存溢出等)。Exception
:表示程序可以捕获或声明抛出的异常情况,包括检查型(checked)和运行时(runtime)异常。
理解 Throwable
层次结构有助于我们明确何时捕获、何时抛出以及如何设计自定义异常。
Throwable 层次结构
java
java.lang.Object
└─ java.lang.Throwable
├─ java.lang.Error
│ ├─ OutOfMemoryError
│ ├─ StackOverflowError
│ └─ ......(其他 JVM 错误)
└─ java.lang.Exception
├─ java.lang.RuntimeException
│ ├─ NullPointerException
│ ├─ IllegalArgumentException
│ └─ ......(其他运行时异常)
├─ java.io.IOException
│ ├─ FileNotFoundException
│ └─ ......(其他 IO 异常)
└─ ......(其他检查型异常)
- 检查型异常(Checked Exception) :非
RuntimeException
的子类,必须在方法签名中throws
或在代码中try-catch
处理。 - 运行时异常(Unchecked Exception) :继承自
RuntimeException
,编译器不强制捕获或声明。 - 错误(Error) :继承自
Error
,通常表示无法恢复的问题,通常不捕获。
Error:无法恢复的严重问题
Error
及其子类表示 JVM
层面的严重故障,一般不做捕获。典型示例:
java
// 模拟栈深度过大导致的 StackOverflowError
public class RecursionDemo {
public static void recurse() {
recurse(); // 递归无终止条件
}
public static void main(String[] args) {
recurse(); // 最终抛出 StackOverflowError
}
}
OutOfMemoryError
:内存不足。StackOverflowError
:调用栈溢出。
这些错误一般不在应用层捕获,而是通过优化代码或调整 JVM
参数来避免。
Exception:可捕获或声明的异常
1. 检查型异常(Checked Exception)
必须显式捕获或声明。常见于 I/O、网络、数据库等操作。
java
public void readFile(String path) throws IOException {
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
System.out.println(br.readLine());
}
}
IOException
、SQLException
等。
2. 运行时异常(Unchecked Exception)
通常表示程序错误,可选择捕获,但不强制。
java
public int divide(int a, int b) {
return a / b; // 若 b == 0,则抛出 ArithmeticException
}
NullPointerException
、IndexOutOfBoundsException
、IllegalArgumentException
等。
自定义异常
1. 自定义检查型异常
java
// 定义异常
public class InsufficientFundsException extends Exception {
public InsufficientFundsException(String msg) {
super(msg);
}
}
// 使用异常
public class BankAccount {
private double balance;
public void withdraw(double amount) throws InsufficientFundsException {
if (amount > balance) {
throw new InsufficientFundsException("余额不足");
}
balance -= amount;
}
}
2. 自定义运行时异常
java
public class InvalidAgeException extends RuntimeException {
public InvalidAgeException(String msg) {
super(msg);
}
}
public class Person {
private int age;
public void setAge(int age) {
if (age < 0 || age > 150) {
throw new InvalidAgeException("年龄不合法: " + age);
}
this.age = age;
}
}
在代码中抛出与捕获
java
public class Demo {
public static void main(String[] args) {
// 捕获并处理自定义检查型异常
BankAccount acct = new BankAccount();
try {
acct.withdraw(1000);
} catch (InsufficientFundsException e) {
System.err.println("操作失败: " + e.getMessage());
}
// 运行时异常示例
Person p = new Person();
try {
p.setAge(-5);
} catch (InvalidAgeException e) {
System.err.println("错误: " + e.getMessage());
}
}
}
- 对检查型异常,必须
try-catch
或在方法签名中throws
。 - 对运行时异常,可根据逻辑选择是否捕获。
小结
Throwable
:所有可抛出类型的基类,分为Error
和Exception
。Error
:无法恢复,一般不捕获。Exception
:可捕获或声明,分为检查型和运行时异常。- 自定义异常 :根据需求继承自
Exception
或RuntimeException
。 - 抛出与捕获 :使用
throw
抛出,try-catch-finally
或try-with-resources
捕获和处理。
通过以上层次结构与代码示例,能够帮助学员更清晰地理解 Java 异常机制及其设计与使用。