异常处理
异常体系
异常层次结构
Throwable
├── Error(错误)
│ ├── VirtualMachineError
│ ├── OutOfMemoryError
│ └── StackOverflowError
└── Exception(异常)
├── IOException
│ ├── FileNotFoundException
│ └── EOFException
├── SQLException
├── RuntimeException(运行时异常)
│ ├── NullPointerException
│ ├── ArrayIndexOutOfBoundsException
│ ├── ArithmeticException
│ ├── ClassCastException
│ └── IllegalArgumentException
└── ...异常分类
| 类型 | 说明 | 示例 |
|---|---|---|
| Error | JVM无法处理的严重错误 | OutOfMemoryError |
| 受检异常 | 编译时必须处理的异常 | IOException、SQLException |
| 运行时异常 | 编译时不强制处理 | NullPointerException |
try-catch-finally
基本语法
java
public class ExceptionDemo {
public static void main(String[] args) {
try {
// 可能出错的代码
int result = 10 / 0;
System.out.println(result);
} catch (ArithmeticException e) {
// 异常处理
System.out.println("除数不能为0");
System.out.println("异常信息: " + e.getMessage());
} finally {
// 无论是否异常都会执行
System.out.println("finally块执行");
}
}
}多个catch块
java
try {
int[] arr = new int[5];
arr[10] = 100; // ArrayIndexOutOfBoundsException
String s = null;
s.length(); // NullPointerException
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("数组越界: " + e.getMessage());
} catch (NullPointerException e) {
System.out.println("空指针异常: " + e.getMessage());
} catch (Exception e) {
System.out.println("其他异常: " + e.getMessage());
}Java 7+ 多异常捕获
java
try {
// 可能抛出多种异常的代码
} catch (IOException | SQLException e) {
System.out.println("IO或SQL异常: " + e.getMessage());
}finally执行顺序
java
public class FinallyDemo {
public static int test() {
try {
return 1;
} finally {
// finally在return之前执行
System.out.println("finally执行");
}
}
public static void main(String[] args) {
System.out.println(test());
}
}
// 输出: finally执行 → 1throw和throws
throw抛出异常
java
public class ThrowDemo {
public static void setAge(int age) {
if (age < 0 || age > 150) {
throw new IllegalArgumentException("年龄必须在0-150之间");
}
System.out.println("年龄设置成功: " + age);
}
public static void main(String[] args) {
try {
setAge(-5);
} catch (IllegalArgumentException e) {
System.out.println("错误: " + e.getMessage());
}
}
}throws声明异常
java
import java.io.FileInputStream;
import java.io.IOException;
public class ThrowsDemo {
// 声明方法可能抛出的异常
public static void readFile(String path) throws IOException {
FileInputStream fis = new FileInputStream(path);
fis.close();
}
public static void main(String[] args) {
try {
readFile("test.txt");
} catch (IOException e) {
System.out.println("文件读取失败: " + e.getMessage());
}
}
}throw vs throws
| throw | throws |
|---|---|
| 抛出异常对象 | 声明方法可能抛出的异常 |
| 在方法体内使用 | 在方法签名上使用 |
| 后跟异常对象 | 后跟异常类型 |
自定义异常
自定义受检异常
java
public class InsufficientBalanceException extends Exception {
private double balance;
private double amount;
public InsufficientBalanceException(double balance, double amount) {
super("余额不足!当前余额: " + balance + ", 需要金额: " + amount);
this.balance = balance;
this.amount = amount;
}
public double getBalance() {
return balance;
}
public double getAmount() {
return amount;
}
}自定义运行时异常
java
public class UserNotFoundException extends RuntimeException {
public UserNotFoundException(String message) {
super(message);
}
public UserNotFoundException(String message, Throwable cause) {
super(message, cause);
}
}使用自定义异常
java
public class BankAccount {
private double balance;
public BankAccount(double balance) {
this.balance = balance;
}
public void withdraw(double amount) throws InsufficientBalanceException {
if (amount > balance) {
throw new InsufficientBalanceException(balance, amount);
}
balance -= amount;
System.out.println("取款成功,余额: " + balance);
}
}
// 使用
BankAccount account = new BankAccount(1000);
try {
account.withdraw(2000);
} catch (InsufficientBalanceException e) {
System.out.println(e.getMessage());
}try-with-resources
Java 7+ 自动资源管理
java
// 传统方式
FileInputStream fis = null;
try {
fis = new FileInputStream("test.txt");
// 使用资源
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// try-with-resources
try (FileInputStream fis = new FileInputStream("test.txt")) {
// 使用资源
// 自动关闭
} catch (IOException e) {
e.printStackTrace();
}多个资源
java
try (FileInputStream fis = new FileInputStream("input.txt");
FileOutputStream fos = new FileOutputStream("output.txt")) {
int data;
while ((data = fis.read()) != -1) {
fos.write(data);
}
} catch (IOException e) {
e.printStackTrace();
}自定义可关闭资源
java
public class MyResource implements AutoCloseable {
private String name;
public MyResource(String name) {
this.name = name;
System.out.println(name + " 创建");
}
public void doSomething() {
System.out.println(name + " 使用中");
}
@Override
public void close() {
System.out.println(name + " 关闭");
}
}
// 使用
try (MyResource r1 = new MyResource("资源1");
MyResource r2 = new MyResource("资源2")) {
r1.doSomething();
r2.doSomething();
}
// 输出: 资源1创建 → 资源2创建 → 使用中 → 资源2关闭 → 资源1关闭异常链
java
public class ExceptionChain {
public static void main(String[] args) {
try {
method1();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void method1() throws Exception {
try {
method2();
} catch (IOException e) {
// 包装异常,保留原始异常
throw new Exception("处理文件时出错", e);
}
}
public static void method2() throws IOException {
throw new IOException("文件不存在");
}
}异常最佳实践
1. 只捕获能处理的异常
java
// 错误做法
try {
// 很多代码
} catch (Exception e) {
// 捕获所有异常
}
// 正确做法
try {
file.read();
} catch (IOException e) {
// 只捕获IO异常
}2. 不要忽略异常
java
// 错误做法
try {
file.read();
} catch (IOException e) {
// 空catch块,忽略异常
}
// 正确做法
try {
file.read();
} catch (IOException e) {
log.error("读取文件失败", e);
throw new RuntimeException("读取文件失败", e);
}3. 使用具体异常类型
java
// 错误做法
throw new Exception("错误");
// 正确做法
throw new IllegalArgumentException("参数不能为空");4. 提供有意义的异常信息
java
// 错误做法
throw new IllegalArgumentException("错误");
// 正确做法
throw new IllegalArgumentException("用户名不能为空");5. 尽早失败
java
public void process(String name, int age) {
// 参数校验放在方法开头
if (name == null || name.isEmpty()) {
throw new IllegalArgumentException("姓名不能为空");
}
if (age < 0 || age > 150) {
throw new IllegalArgumentException("年龄必须在0-150之间");
}
// 正常业务逻辑
}常见异常
| 异常 | 原因 | 解决方案 |
|---|---|---|
| NullPointerException | 访问null对象的成员 | 添加null检查 |
| ArrayIndexOutOfBoundsException | 数组索引越界 | 检查索引范围 |
| ArithmeticException | 算术错误(如除零) | 检查除数 |
| ClassCastException | 类型转换错误 | 使用instanceof检查 |
| NumberFormatException | 数字格式错误 | 校验输入格式 |
| IllegalArgumentException | 非法参数 | 检查参数有效性 |