Java异常体系
Java异常体系[编辑 | 编辑源代码]
概述[编辑 | 编辑源代码]
Java异常体系是Java语言中用于处理程序运行时错误的机制框架。当程序在运行过程中出现意外情况(如除以零、空指针访问等)时,Java会抛出(throw)一个异常对象,程序可以捕获(catch)并处理这个异常,从而保证程序的健壮性。
Java异常体系的核心特点是:
- 继承层次结构:所有异常类型都是
java.lang.Throwable
的子类 - 分类处理:分为检查型异常(Checked Exception)和非检查型异常(Unchecked Exception)
- 传播机制:异常会沿着方法调用栈向上传播,直到被捕获或导致程序终止
异常分类[编辑 | 编辑源代码]
Java异常体系主要分为三大类:
1. Error[编辑 | 编辑源代码]
表示JVM本身的严重错误,应用程序通常无法处理。例如:
OutOfMemoryError
StackOverflowError
VirtualMachineError
2. 检查型异常(Checked Exception)[编辑 | 编辑源代码]
继承自Exception
但不属于RuntimeException
的异常,编译器会强制检查。常见例子:
IOException
SQLException
ClassNotFoundException
3. 非检查型异常(Unchecked Exception)[编辑 | 编辑源代码]
继承自RuntimeException
的异常,编译器不强制处理。常见例子:
NullPointerException
ArrayIndexOutOfBoundsException
IllegalArgumentException
异常处理机制[编辑 | 编辑源代码]
Java通过五个关键字实现异常处理:try
, catch
, finally
, throw
, throws
基本语法[编辑 | 编辑源代码]
try {
// 可能抛出异常的代码
} catch (ExceptionType1 e1) {
// 处理ExceptionType1类型的异常
} catch (ExceptionType2 e2) {
// 处理ExceptionType2类型的异常
} finally {
// 无论是否发生异常都会执行的代码
}
示例:文件读取[编辑 | 编辑源代码]
import java.io.*;
public class FileExample {
public static void main(String[] args) {
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader("test.txt"));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (FileNotFoundException e) {
System.err.println("文件未找到: " + e.getMessage());
} catch (IOException e) {
System.err.println("IO错误: " + e.getMessage());
} finally {
try {
if (reader != null) {
reader.close();
}
} catch (IOException e) {
System.err.println("关闭文件时出错: " + e.getMessage());
}
}
}
}
可能的输出:
文件未找到: test.txt (系统找不到指定的文件。)
自定义异常[编辑 | 编辑源代码]
可以创建自己的异常类来代表特定问题:
// 自定义检查型异常
class InsufficientFundsException extends Exception {
private double amount;
public InsufficientFundsException(double amount) {
super("资金不足,缺少: " + amount);
this.amount = amount;
}
public double getAmount() {
return amount;
}
}
// 使用示例
class BankAccount {
private double balance;
public void withdraw(double amount) throws InsufficientFundsException {
if (amount > balance) {
throw new InsufficientFundsException(amount - balance);
}
balance -= amount;
}
}
最佳实践[编辑 | 编辑源代码]
1. 具体异常优先:捕获最具体的异常类型,而不是直接捕获Exception
2. 不要忽略异常:至少记录异常信息
3. 合理使用finally:释放资源应放在finally块中
4. 避免空的catch块:这会隐藏错误
5. 异常与业务逻辑分离:不要用异常控制正常流程
异常链[编辑 | 编辑源代码]
Java支持异常链,可以将底层异常包装为高层异常:
try {
// 可能抛出SQLException的代码
} catch (SQLException e) {
throw new ServiceException("数据库操作失败", e);
}
性能考虑[编辑 | 编辑源代码]
异常处理会带来性能开销,特别是在频繁执行的代码路径中。对于可预见的错误条件,考虑使用返回值而不是异常。
异常实例的构造开销主要来自:
- 填充异常栈轨迹(可通过重写
fillInStackTrace()
优化) - 异常对象的创建本身
数学表示[编辑 | 编辑源代码]
异常处理的概率模型可以表示为:
解析失败 (语法错误): {\displaystyle P(程序终止) = \prod_{i=1}^{n} (1 - P(处理异常_i)) }
其中解析失败 (语法错误): {\displaystyle P(处理异常_i)} 表示第i层异常被处理的概率。
实际案例[编辑 | 编辑源代码]
电商系统库存检查:
public class InventoryService {
public void reserveItem(String itemId, int quantity)
throws InventoryException {
try {
// 检查库存
int available = checkInventoryDB(itemId);
if (available < quantity) {
throw new InventoryException(
"库存不足,请求: " + quantity +
", 可用: " + available);
}
// 更新库存...
} catch (SQLException e) {
throw new InventoryException("数据库访问失败", e);
}
}
}
常见面试问题[编辑 | 编辑源代码]
1. Error和Exception的区别是什么? 2. 检查型异常和非检查型异常的主要区别? 3. finally块在什么情况下不会执行? 4. 解释异常链的概念及其用途 5. 为什么不应该用异常来控制程序流程?