在 Java 中,异常(Exception)是程序运行时出现的非预期情况,会中断正常执行流程。Java 异常体系以 为根类,分为
Throwable(错误) 和
Error(异常) 两大分支,各自包含不同类型的异常情况。以下是详细讲解:
Exception
一、异常体系结构
Throwable(所有异常/错误的根类)
├─ Error(错误):JVM 无法处理的严重问题,程序通常无法恢复
│ ├─ VirtualMachineError(虚拟机错误)
│ │ ├─ OutOfMemoryError(OOM,内存溢出)
│ │ └─ StackOverflowError(栈溢出)
│ ├─ NoClassDefFoundError(类定义未找到,运行时类缺失)
│ └─ AWTError(GUI 组件错误,如图形环境异常)
│
└─ Exception(异常):程序可处理的问题,分两类
├─ 受检异常(Checked Exception):编译期必须处理(捕获或声明抛出)
│ ├─ IOException(I/O 操作异常)
│ │ ├─ FileNotFoundException(文件未找到)
│ │ └─ EOFException(文件读取到末尾)
│ ├─ SQLException(数据库操作异常)
│ ├─ ClassNotFoundException(反射时类未找到)
│ └─ InterruptedException(线程被中断异常)
│
└─ 非受检异常(Unchecked Exception):编译期无需处理,运行时可能出现
├─ RuntimeException(运行时异常,非受检异常的核心)
│ ├─ NullPointerException(空指针异常,调用 null 对象的方法/属性)
│ ├─ IndexOutOfBoundsException(索引越界,如数组/集合下标超范围)
│ │ ├─ ArrayIndexOutOfBoundsException(数组索引越界)
│ │ └─ StringIndexOutOfBoundsException(字符串索引越界)
│ ├─ ClassCastException(类型转换异常,如将 String 强转为 Integer)
│ ├─ ArithmeticException(算术异常,如除以 0)
│ ├─ IllegalArgumentException(参数非法,如传递不符合要求的参数)
│ └─ NumberFormatException(数字格式异常,如 "abc" 转 int)
│
└─ 其他非 RuntimeException 的非受检异常(极少,如 ThreadDeath)
二、核心分类详解
1. Error(错误)
本质:由 JVM 生成,代表系统级的严重错误,超出程序本身的处理能力,通常是不可恢复的。
特点:程序无需捕获或处理(也无法有效处理),需通过修改代码或调整环境解决。
常见类型:
:栈内存溢出,通常因递归调用无终止条件(每次递归都会占用栈空间)。
StackOverflowError
public void recursive() {
recursive(); // 无限递归,最终抛出 StackOverflowError
}
(OOM):堆内存溢出,如创建大量对象且未被垃圾回收(如循环创建对象存入集合)。
OutOfMemoryError
:编译时存在的类,运行时因类路径错误或类被删除而无法找到。
NoClassDefFoundError
2. Exception(异常
程序可通过代码处理的异常,分为 受检异常 和 非受检异常,核心区别在于编译期是否强制检查。
(1)受检异常(Checked Exception)
定义:所有非 及其子类的异常,编译期必须显式处理(捕获或声明抛 出),否则编译报错。
RuntimeException
设计目的:提醒开发者处理可预见的外部依赖风险(如文件操作、网络请求可能失败)。
常见类型及场景:
:I/O 操作相关异常,如文件读写、网络传输失败。
IOException
子类 :试图读取不存在的文件时抛出。
FileNotFoundException
:数据库操作异常,如连接失败、SQL 语法错误、表不存在等。
SQLException:通过反射(如
ClassNotFoundException)加载类时,类未找到。
Class.forName("com.example.User"):线程在休眠(
InterruptedException)或等待(
sleep)时被其他线程中断。
wait
处理示例:
必须通过 捕获或
try-catch 声明,否则编译不通过:
throws
// 编译报错:未处理 IOException
public void readFile() {
FileReader fr = new FileReader("test.txt"); // FileReader 构造方法声明抛出 IOException
}
// 正确处理方式 1:声明抛出
public void readFile() throws IOException {
FileReader fr = new FileReader("test.txt");
}
// 正确处理方式 2:捕获并处理
public void readFile() {
try {
FileReader fr = new FileReader("test.txt");
} catch (IOException e) {
System.out.println("文件读取失败:" + e.getMessage());
}
}
(2)非受检异常(Unchecked Exception)
定义: 及其子类(或特殊的非
RuntimeException 类型,如
Exception),编 译期不强制处理,运行时才可能抛出。
ThreadDeath
设计目的:通常由程序逻辑错误导致,应通过代码优化避免(而非依赖 )。
try-catch
常见类型及场景:
Nu(NPE):最常见异常,当调用
llPointerException 对象的方法或属性时抛出。
null
String s = null;
s.length(); // 抛出 NPE,因 s 为 null
I:索引超出容器范围(如数组、
ndexOutOfBoundsException、
ArrayList)。
String
int[] arr = new int[3];
arr[5] = 10; // 数组索引越界(ArrayIndexOutOfBoundsException)
C:类型强制转换失败,如将父类对象转为不兼容的子类。
lassCastException
Object obj = "hello";
Integer num = (Integer) obj; // 抛出 ClassCastException(String 不能转 Integer)
A:算术运算错误,典型场景是除以 0。
rithmeticException
int result = 10 / 0; // 抛出 ArithmeticException
I:方法接收非法参数,如传递负数给要求正数的方法。
llegalArgumentException
public void setAge(int age) {
if (age < 0) {
throw new IllegalArgumentException("年龄不能为负数");
}
}
N:字符串转数字失败(如非数字字符串转
umberFormatException)。
int
Integer.parseInt("abc"); // 抛出 NumberFormatException
三、异常处理机制
Java 通过 、
try-catch-finally、
throws 关键字实现异常处理:
throw
:包裹可能抛出异常的代码块。
try:捕获并处理指定类型的异常(可多个
catch 块,按 “子类在前、父类在后” 顺序排列)。
catch:无论是否发生异常,都会执行(常用于释放资源,如关闭文件流、数据库连接)。
finally:在方法声明处标注可能抛出的异常,由调用者处理。
throws:主动抛出异常对象(如检测到非法参数时)。
throw
示例:
public int divide(int a, int b) {
if (b == 0) {
throw new ArithmeticException("除数不能为 0"); // 主动抛出异常
}
return a / b;
}
public static void main(String[] args) {
try {
int result = new Demo().divide(10, 0);
System.out.println("结果:" + result);
} catch (ArithmeticException e) {
System.out.println("捕获异常:" + e.getMessage()); // 处理异常
} finally {
System.out.println("无论是否异常,都会执行"); // 释放资源等操作
}
}
// 输出:
// 捕获异常:除数不能为 0
// 无论是否异常,都会执行
四、总结
Error:严重错误,程序无法处理,需通过代码优化或环境调整避免(如避免内存泄漏、控制递归深度)。受检异常:编译期强制处理,与外部交互相关(如文件、数据库),需显式捕获或声明。非受检异常:运行时异常,多为逻辑错误(如 NPE、索引越界),应通过代码健壮性避免。
合理使用异常处理可提高程序稳定性,但需避免滥用(如用异常代替正常逻辑判断、捕获所有异常),同时注意资源释放(推荐使用 try-with-resources 自动关闭资源)。















暂无评论内容