异常处理¶
📖 章节简介¶
本章将介绍Java的异常处理机制,包括try-catch语句、自定义异常和异常链。
上图概括了 try/catch/finally 与 throw/throws 的关系,便于建立异常处理闭环。
⚠️ 异常基础¶
1. 异常层次结构¶
Java
// 异常层次结构
/*
Throwable
├── Error(错误)
│ ├── OutOfMemoryError
│ ├── StackOverflowError
│ └── VirtualMachineError
└── Exception(异常)
├── RuntimeException(运行时异常)
│ ├── NullPointerException
│ ├── ArrayIndexOutOfBoundsException
│ └── IllegalArgumentException
├── IOException(IO异常)
│ ├── FileNotFoundException
│ └── EOFException
└── SQLException(SQL异常)
*/
2. 异常类型¶
Java
import java.io.*;
// 异常类型示例
public class ExceptionTypes {
public static void main(String[] args) {
// 受检异常(Checked Exception)
try {
FileReader file = new FileReader("nonexistent.txt");
} catch (FileNotFoundException e) {
System.out.println("文件未找到: " + e.getMessage());
}
// 运行时异常(Unchecked Exception)
String str = null;
try {
int length = str.length(); // NullPointerException
} catch (NullPointerException e) {
System.out.println("空指针异常: " + e.getMessage());
}
// 错误(Error)
try {
int[] array = new int[Integer.MAX_VALUE];
} catch (OutOfMemoryError e) {
System.out.println("内存溢出: " + e.getMessage());
}
}
}
🛡️ 异常处理¶
1. try-catch-finally¶
Java
// try-catch-finally
public class TryCatchFinally {
public static void main(String[] args) {
// 基本异常处理
try {
int result = divide(10, 0);
System.out.println("结果: " + result);
} catch (ArithmeticException e) {
System.out.println("算术异常: " + e.getMessage());
} finally {
System.out.println("finally块总是执行");
}
// 多个catch块
try {
String str = null;
System.out.println(str.length());
} catch (NullPointerException e) {
System.out.println("空指针异常");
} catch (IllegalArgumentException e) {
System.out.println("非法参数异常");
} catch (Exception e) {
System.out.println("其他异常: " + e.getMessage());
}
}
public static int divide(int a, int b) {
return a / b;
}
}
2. try-with-resources¶
Java
// try-with-resources(Java 7+)
import java.io.*;
public class TryWithResources {
public static void main(String[] args) {
// 传统方式
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader("file.txt"));
String line = reader.readLine();
System.out.println(line);
} catch (IOException e) {
System.out.println("IO异常: " + e.getMessage());
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
System.out.println("关闭异常: " + e.getMessage());
}
}
}
// 使用try-with-resources
try (BufferedReader reader2 = new BufferedReader(new FileReader("file.txt"))) { // try-with-resources 自动关闭资源
String line = reader2.readLine();
System.out.println(line);
} catch (IOException e) {
System.out.println("IO异常: " + e.getMessage());
}
// 资源自动关闭
}
}
🎯 自定义异常¶
1. 创建自定义异常¶
Java
// 自定义异常
public class InsufficientFundsException extends Exception {
private double balance;
private double amount;
public InsufficientFundsException(double balance, double amount) {
super("余额不足,当前余额: " + balance + ",需要金额: " + amount);
this.balance = balance;
this.amount = amount;
}
public double getBalance() {
return balance;
}
public double getAmount() {
return amount;
}
}
// 使用自定义异常(与InsufficientFundsException分属不同文件)
class BankAccount {
private double balance;
public BankAccount(double initialBalance) {
this.balance = initialBalance;
}
public void withdraw(double amount) throws InsufficientFundsException {
if (amount > balance) {
throw new InsufficientFundsException(balance, amount);
}
balance -= amount;
System.out.println("取款成功,余额: " + balance);
}
public static void main(String[] args) {
BankAccount account = new BankAccount(1000);
try {
account.withdraw(500);
account.withdraw(600); // 会抛出异常
} catch (InsufficientFundsException e) {
System.out.println(e.getMessage());
System.out.println("当前余额: " + e.getBalance());
System.out.println("需要金额: " + e.getAmount());
}
}
}
📊 异常链¶
1. 异常链¶
Java
// 异常链
public class ExceptionChain {
public static void main(String[] args) {
try {
method1();
} catch (Exception e) {
System.out.println("捕获异常: " + e.getMessage());
System.out.println("原因: " + e.getCause().getMessage());
// 打印异常栈
e.printStackTrace();
}
}
public static void method1() throws Exception {
try {
method2();
} catch (Exception e) {
// 包装原始异常
throw new Exception("method1失败", e);
}
}
public static void method2() throws Exception {
try {
int result = 10 / 0;
} catch (ArithmeticException e) {
// 包装原始异常
throw new Exception("method2失败", e);
}
}
}
💡 最佳实践¶
1. 异常处理原则¶
Java
import java.io.*;
// 异常处理最佳实践
public class ExceptionBestPractices {
// ✅ 好的做法:捕获具体异常
public void readFile1() {
try {
FileReader reader = new FileReader("file.txt");
} catch (FileNotFoundException e) {
System.out.println("文件未找到");
} catch (IOException e) {
System.out.println("IO错误");
}
}
// ❌ 不好的做法:捕获所有异常
public void readFile2() {
try {
FileReader reader = new FileReader("file.txt");
} catch (Exception e) {
System.out.println("发生异常"); // 太宽泛
}
}
// ✅ 好的做法:使用try-with-resources
public void readFile3() {
try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) {
String line = reader.readLine();
System.out.println(line);
} catch (IOException e) {
System.out.println("IO错误");
}
}
// ❌ 不好的做法:忽略异常
public void readFile4() {
try {
FileReader reader = new FileReader("file.txt");
} catch (IOException e) {
// 什么都不做
}
}
}
2. 异常设计¶
Java
// 异常设计最佳实践
public class ExceptionDesign {
// ✅ 好的做法:提供有用的错误信息
public class InvalidEmailException extends Exception {
public InvalidEmailException(String email) {
super("无效的邮箱地址: " + email);
}
}
// ❌ 不好的做法:错误信息不明确
public class BadException extends Exception {
public BadException() {
super("出错了"); // 太模糊
}
}
// ✅ 好的做法:继承适当的异常类
public class UserNotFoundException extends RuntimeException {
public UserNotFoundException(String username) {
super("用户不存在: " + username);
}
}
// ☕ 需要根据场景选择:对于业务逻辑异常,通常更适合继承RuntimeException
public class UserException extends Exception {
// 如果不需要强制调用方处理,考虑继承RuntimeException
}
}
📝 练习题¶
基础题¶
- 什么是异常?有哪些类型?
- try-catch-finally如何工作?
- 如何创建自定义异常?
进阶题¶
- 使用try-with-resources管理资源。
- 实现异常链。
- 设计合理的异常层次结构。
实践题¶
- 创建一个文件处理工具。
- 实现一个银行账户系统。
- 构建一个网络请求工具类。
📚 推荐阅读¶
🔗 下一章¶
集合框架 - 学习Java的集合框架。