一、介绍
本文介绍Java中的异常相关知识,通过实例演示异常的出现和解决方法,以及异常的体系结构、核心语法、注意事项等,下面将进行详细解析。
**二、**Java 异常核心语法
1.try-catch-finally:捕获并处理异常
java
try {
// 可能抛出异常的代码
} catch (异常类型1 e) {
// 处理异常类型1
} catch (异常类型2 e) { // 多个catch需按"从小到大"(子类在前)
// 处理异常类型2
} finally {
// 无论是否异常,必执行(除非JVM退出)
}
2.throw:手动抛出异常
java
if (参数不合法) {
throw new IllegalArgumentException("参数错误"); // 手动抛异常
}
3.throws:声明方法可能抛出的异常
java
public void readFile() throws IOException { // 声明可能抛IOException
// 读取文件(可能触发IOException)
}
4.try-with-resources:自动关闭资源(实现AutoCloseable接口)
java
try (FileReader fr = new FileReader("test.txt")) { // 资源自动关闭
fr.read();
} catch (IOException e) {
e.printStackTrace();
}
**三、**常见异常示例及解决
1.NullPointerException(空指针异常)
场景:调用 null 对象的方法或属性。


解决:


2. IndexOutOfBoundsException(索引越界)
场景 :数组 / 集合索引超出范围(如ArrayIndexOutOfBoundsException、StringIndexOutOfBoundsException)。
数组示例


解决:


集合示例


解决:


3. ClassCastException(类型转换异常)
场景:强制转换不兼容的类型。


解决:


4. ArithmeticException(算术异常)
场景:除以 0 等非法算术操作。


解决:


5. IllegalArgumentException(非法参数异常)
场景:方法接收的参数不符合预期(如参数为负数但业务要求必须为正数)。


6. IOException(IO 异常,Checked 异常)
场景:文件读写等 IO 操作失败。
java
import java.io.FileReader;
import java.io.IOException;
public class IOExceptionDemo {
// 方法1:用throws声明异常(交给调用者处理)
public static void readFile1() throws IOException {
FileReader fr = new FileReader("nonexistent.txt"); // 文件不存在时抛IOException
fr.close();
}
// 方法2:用try-catch处理异常
public static void readFile2() {
try (FileReader fr = new FileReader("nonexistent.txt")) { // try-with-resources自动关闭
fr.read();
} catch (IOException e) {
System.out.println("IO异常:" + e.getMessage());
}
}
public static void main(String[] args) {
try {
readFile1(); // 调用声明throws的方法,必须处理
} catch (IOException e) {
e.printStackTrace();
}
readFile2(); // 已内部处理,无需额外操作
}
}
四、异常相关知识问题
1. Checked 异常和 Unchecked 异常的区别?
- Checked 异常 :继承自
Exception(非RuntimeException),编译时强制处理(try-catch或throws),如IOException。 - Unchecked 异常 :继承自
RuntimeException,编译时不强制处理,通常是代码逻辑错误(如空指针),运行时触发。
2. final、finally、finalize的区别?
final:修饰符,可修饰类(不可继承)、方法(不可重写)、变量(不可修改)。finally:异常处理块,与try搭配,无论是否抛出异常都会执行(除非 JVM 退出),常用于释放资源。finalize:Object类的方法,垃圾回收前调用,用于资源清理(不推荐使用,Java 9 后标记为过时)。
3. try-catch-finally中return的执行顺序?
try或catch中的return会先执行,但结果会暂存,然后执行finally。- 若
finally中也有return,会覆盖try/catch的返回值。
4. throw和throws的区别?
throw:用于方法内部,手动抛出具体异常对象(如throw new IOException())。throws:用于方法声明处,声明方法可能抛出的异常类型(如public void m() throws IOException),告知调用者需处理。
5. 异常处理的最佳实践?
- 避免捕获所有异常(
catch (Exception e)),应捕获具体异常。 - 不要忽略异常(空
catch块),至少记录日志。 - 用
try-with-resources自动关闭资源(替代finally手动关闭)。 - 异常信息需具体(包含上下文,如 "文件 xxx 不存在")。
- 自定义异常时,区分 Checked/Unchecked(业务异常推荐 Unchecked)。
五、异常体系结构与概括
1. 异常体系结构
bash
Throwable(顶层类)
├─ Error(错误:JVM层面的严重问题,程序无法处理)
│ ├─ VirtualMachineError(虚拟机错误)
│ │ ├─ OutOfMemoryError(内存溢出)
│ │ ├─ StackOverflowError(栈溢出)
│ │ └─ InternalError(内部错误)
│ ├─ AWTError(AWT组件错误)
│ └─ LinkageError(类链接错误)
│ ├─ NoClassDefFoundError(类定义未找到)
│ └─ UnsatisfiedLinkError(本地方法链接失败)
│
└─ Exception(异常:程序可处理的问题)
├─ RuntimeException(运行时异常:非检查型,编译不强制处理)
│ ├─ NullPointerException(空指针)
│ ├─ IndexOutOfBoundsException(索引越界)
│ ├─ ClassCastException(类型转换)
│ ├─ IllegalArgumentException(非法参数)
│ ├─ ArithmeticException(算术错误)
│ └─ ConcurrentModificationException(并发修改)
│
└─ 受检异常(Checked Exception:编译强制处理)
├─ IOException(IO操作异常)
│ ├─ FileNotFoundException(文件未找到)
│ └─ IOException(通用IO错误)
├─ SQLException(数据库操作异常)
├─ ClassNotFoundException(类未找到)
└─ InterruptedException(线程中断)
2. Error(错误):不可处理的严重问题
| 错误类型 | 含义 | 常见场景 | 解决方式 |
|---|---|---|---|
OutOfMemoryError |
内存溢出(JVM 堆 / 方法区不足) | 创建大量对象未释放、大文件加载 | 1. 调大 JVM 内存参数(-Xms/-Xmx)2. 优化对象生命周期,避免内存泄漏 |
StackOverflowError |
栈溢出(方法调用栈深度超过限制) | 递归调用无终止条件、多层嵌套方法 | 1. 修复递归终止条件2. 减少方法嵌套层级 |
NoClassDefFoundError |
运行时找不到类定义(编译存在,运行缺失) | 类路径(classpath)配置错误、jar 包缺失 | 1. 检查类路径是否包含目标类2. 确保依赖 jar 包存在 |
UnsatisfiedLinkError |
本地方法(JNI)链接失败 | 调用的本地库(.dll/.so)不存在或版本不匹配 | 1. 检查本地库路径是否正确2. 确保库文件与系统兼容 |
3. Exception(异常):可处理的问题
3.1 运行时异常(RuntimeException):非检查型异常
特点:编译时不强制处理,通常由程序逻辑错误导致,需通过代码优化避免。
| 异常类型 | 含义 | 常见场景 | 解决方式 |
|---|---|---|---|
NullPointerException |
调用 null 对象的方法 / 属性 | String s = null; s.length(); |
1. 调用前判空(if (obj != null))2. 使用Optional类避免空指针 |
IndexOutOfBoundsException |
数组 / 集合索引越界 | List<String> list = new ArrayList<>(); list.get(0); |
1. 访问前检查索引范围(index < size)2. 使用循环时避免硬编码索引 |
ClassCastException |
类型强制转换失败 | Object obj = "str"; Integer i = (Integer) obj; |
1. 转换前用instanceof判断类型2. 避免无意义的强制转换 |
IllegalArgumentException |
方法接收非法参数 | 传入负数到要求正数的方法(如new ArrayList(-1)) |
1. 方法内校验参数合法性2. 调用前确保参数符合要求 |
ArithmeticException |
算术错误(如除以 0) | int a = 1 / 0; |
1. 避免除数为 02. 计算前校验除数合法性 |
ConcurrentModificationException |
迭代集合时并发修改(如边遍历边删除) | for (String s : list) { list.remove(s); } |
1. 使用迭代器的remove()方法2. 使用CopyOnWriteArrayList等线程安全集合 |
3.2 受检异常(Checked Exception):编译时强制处理
特点:编译器要求必须捕获或声明抛出,通常由外部环境导致(如 IO、网络问题)。
| 异常类型 | 含义 | 常见场景 | 解决方式 |
|---|---|---|---|
IOException |
IO 操作失败(读 / 写文件、网络流) | 读取不存在的文件、网络中断时写数据 | 1. 捕获异常并处理(如提示 "文件不存在")2. 确保资源路径正确,网络通畅 |
FileNotFoundException |
找不到指定文件 / 目录(IOException子类) |
new FileInputStream("不存在的文件.txt") |
1. 检查文件路径是否正确2. 操作前判断文件是否存在(file.exists()) |
SQLException |
数据库操作失败 | 连接参数错误、SQL 语法错误、表不存在 | 1. 检查数据库连接配置和 SQL 语句2. 打印异常信息定位具体错误(如e.getMessage()) |
ClassNotFoundException |
加载类时找不到类定义(与NoClassDefFoundError的区别:前者是主动加载失败,后者是被动引用失败) |
Class.forName("com.mysql.Driver") |
1. 检查类全限定名是否正确2. 确保依赖的 jar 包已引入 |
InterruptedException |
线程在等待 / 休眠时被中断 | Thread.sleep(1000)时调用thread.interrupt() |
1. 捕获后可恢复中断状态(Thread.currentThread().interrupt())2. 根据业务决定是否终止线程 |