深入学习Java异常的概念、分类体系、异常处理机制和最佳实践
异常(Exception)是程序运行过程中出现的非正常情况,它会中断程序的正常执行流程。Java提供了完善的异常处理机制来处理这些异常情况。
// 空指针异常示例
String str = null;
int length = str.length(); // 抛出 NullPointerException
// 数组越界异常示例
int[] array = {1, 2, 3};
int value = array[5]; // 抛出 ArrayIndexOutOfBoundsException
// 算术异常示例
int result = 10 / 0; // 抛出 ArithmeticException
Java异常采用层次结构设计,所有异常都继承自Throwable
类。
Throwable ├── Error │ ├── OutOfMemoryError │ ├── StackOverflowError │ └── VirtualMachineError └── Exception ├── RuntimeException (运行时异常) │ ├── NullPointerException │ ├── ArrayIndexOutOfBoundsException │ ├── ArithmeticException │ └── NumberFormatException └── 检查异常 ├── IOException ├── ClassNotFoundException └── SQLException
检查异常是编译时必须处理的异常,继承自Exception
但不是RuntimeException
。
异常类型 | 描述 | 常见场景 |
---|---|---|
IOException | 输入输出异常 | 文件读写、网络通信 |
ClassNotFoundException | 类未找到异常 | 动态加载类 |
SQLException | 数据库异常 | 数据库操作 |
InterruptedException | 线程中断异常 | 多线程编程 |
// 检查异常示例
try {
FileReader file = new FileReader("test.txt");
// 文件操作
} catch (FileNotFoundException e) {
System.out.println("文件未找到: " + e.getMessage());
}
运行时异常是编译时不强制处理的异常,继承自RuntimeException
。
异常类型 | 描述 | 常见原因 |
---|---|---|
NullPointerException | 空指针异常 | 对null引用调用方法 |
ArrayIndexOutOfBoundsException | 数组越界异常 | 访问超出数组范围的索引 |
ArithmeticException | 算术异常 | 除零操作 |
NumberFormatException | 数字格式异常 | 字符串转数字格式错误 |
IllegalArgumentException | 非法参数异常 | 方法参数不合法 |
// 运行时异常示例
try {
String str = "abc";
int number = Integer.parseInt(str); // NumberFormatException
} catch (NumberFormatException e) {
System.out.println("数字格式错误: " + e.getMessage());
}
错误表示严重的系统问题,通常不应该被捕获。
错误类型 | 描述 | 常见原因 |
---|---|---|
OutOfMemoryError | 内存不足错误 | 堆内存耗尽 |
StackOverflowError | 栈溢出错误 | 递归调用过深 |
NoClassDefFoundError | 类定义未找到错误 | 运行时找不到类文件 |
try {
// 可能抛出异常的代码
} catch (SpecificException e) {
// 处理特定异常
} catch (Exception e) {
// 处理其他异常
} finally {
// 总是执行的代码
}
public void processData(String data) {
try {
// 可能抛出多种异常的代码
int length = data.length(); // NullPointerException
int number = Integer.parseInt(data); // NumberFormatException
int result = 100 / number; // ArithmeticException
System.out.println("处理结果: " + result);
} catch (NullPointerException e) {
System.out.println("数据为null");
} catch (NumberFormatException e) {
System.out.println("数据格式不正确");
} catch (ArithmeticException e) {
System.out.println("除零操作");
} catch (Exception e) {
System.out.println("未知错误: " + e.getMessage());
} finally {
System.out.println("处理完成");
}
}
// 好的做法
try {
int number = Integer.parseInt(input);
} catch (NumberFormatException e) {
// 处理具体异常
System.out.println("输入格式错误: " + input);
}
public void validateAge(int age) {
if (age < 0) {
throw new IllegalArgumentException(
String.format("年龄不能为负数,当前值: %d", age)
);
}
}
InputStream input = null;
try {
input = new FileInputStream("file.txt");
// 使用资源
} catch (IOException e) {
System.out.println("文件操作异常: " + e.getMessage());
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
System.out.println("关闭文件异常: " + e.getMessage());
}
}
}
// 错误做法
try {
riskyOperation();
} catch (Exception e) {
// 什么都不做 - 这是错误的!
}
// 错误做法
try {
specificOperation();
} catch (Exception e) {
// 太宽泛,应该捕获具体异常
}
// 错误做法
try {
return array[index];
} catch (ArrayIndexOutOfBoundsException e) {
return null;
}
// 正确做法
if (index >= 0 && index < array.length) {
return array[index];
} else {
return null;
}
// 性能对比示例
// 坏做法:用异常控制流程(性能差)
for (int i = 0; i < 1000; i++) {
try {
if (i % 2 == 0) {
throw new Exception("偶数");
}
} catch (Exception e) {
// 处理偶数
}
}
// 好做法:用条件判断(性能好)
for (int i = 0; i < 1000; i++) {
if (i % 2 == 0) {
// 处理偶数
}
}
A: 当你能够合理地处理异常或需要进行资源清理时。
A: 检查异常必须在编译时处理,运行时异常可以选择处理。
A: 通常不应该,Error表示严重的系统问题,程序无法恢复。
A: 异常用于异常情况,错误码用于预期的错误状态。