二、异常(完整版)
(一)什么是异常?
如果一个方法不能以正常的方式完成它的任务,就会选择这个退出路径。在这种情况下,方法不会返回一个值,而是抛出(throw)一个封装了错误信息的对象。需要注意的是,这个方法会立刻上推出,并不返回值。
Java 中的错误可以分成两类:
- 编译时错误:语法错误,编译器能够发现并报错
- 运行时错误:可以正常通过编译,语法正确,但是逻辑有错,不好发现
Java 中专门有一组类来表示各种各样的运行时错误,称之为异常类。
(二)异常的使用
当程序出现异常时,会生成一个异常对象,把这个对象"扔出去",由一个能处理这个对象的程序接收它。
1. try-catch 基本语法
try {
// 可能抛出异常的代码
} catch (ExceptionType e) {
// 异常处理代码
}
2. 异常类层次结构
Java 中所有异常类的基类是 Throwable,它有两个主要子类:
Error:系统级错误,程序无法处理(如内存溢出)Exception:程序可以处理的异常

提示
如果出现 RuntimeException 异常,那么一定是你的问题
(三)异常类体系
1. Throwable 类的主要方法
public String getMessage() // 返回异常的详细信息
public String toString() // 返回异常的简要描述
public void printStackTrace() // 打印异常堆栈跟踪信息
2. Exception 类的分类
检查型异常 (Checked Exception):编译器要求必须处理的异常
- 如:IOException、SQLException
- 必须使用 try-catch 或 throws 声明
非检查型异常 (Unchecked Exception):编译器不强制处理的异常
- 如:RuntimeException 及其子类
- 包括:NullPointerException、ArrayIndexOutOfBoundsException 等
(四)异常处理机制
1. try-catch-finally
try {
// 可能抛出异常的代码
FileReader file = new FileReader("test.txt");
} catch (FileNotFoundException e) {
// 处理文件未找到异常
System.out.println("文件未找到:" + e.getMessage());
} catch (IOException e) {
// 处理其他 IO 异常
System.out.println("IO 错误:" + e.getMessage());
} finally {
// 无论是否发生异常都会执行的代码
System.out.println("程序执行结束");
}
2. throws 声明
public void readFile() throws IOException {
FileReader file = new FileReader("test.txt");
// 读取文件操作
}
3. throw 抛出异常
public void validateAge(int age) {
if (age < 0) {
throw new IllegalArgumentException("年龄不能为负数");
}
}
(五)自定义异常
1. 创建自定义异常类
// 继承 Exception 创建检查型异常
public class MyCheckedException extends Exception {
public MyCheckedException(String message) {
super(message);
}
}
// 继承 RuntimeException 创建非检查型异常
public class MyUncheckedException extends RuntimeException {
public MyUncheckedException(String message) {
super(message);
}
}
2. 使用自定义异常
public class BankAccount {
private double balance;
public void withdraw(double amount) throws InsufficientFundsException {
if (amount > balance) {
throw new InsufficientFundsException("余额不足,当前余额:" + balance);
}
balance -= amount;
}
}
class InsufficientFundsException extends Exception {
public InsufficientFundsException(String message) {
super(message);
}
}
(六)异常处理的最佳实践
1. 具体异常优先
// 不推荐
try {
// 代码
} catch (Exception e) {
// 处理所有异常
}
// 推荐
try {
// 代码
} catch (FileNotFoundException e) {
// 处理特定异常
} catch (IOException e) {
// 处理 IO 异常
}
2. 不要忽略异常
// 不推荐 - 忽略异常
try {
// 代码
} catch (Exception e) {
// 什么都不做
}
// 推荐 - 至少记录异常
try {
// 代码
} catch (Exception e) {
e.printStackTrace(); // 至少打印堆栈跟踪
// 或者记录到日志文件
}
3. 使用 finally 释放资源
Connection conn = null;
try {
conn = DriverManager.getConnection(url, user, password);
// 使用连接
} catch (SQLException e) {
// 处理异常
} finally {
if (conn != null) {
try {
conn.close(); // 确保资源被释放
} catch (SQLException e) {
// 记录关闭异常
}
}
}
4. 使用 try-with-resources(Java 7+)
// 自动关闭资源
try (FileReader reader = new FileReader("file.txt");
BufferedReader br = new BufferedReader(reader)) {
// 使用资源
String line = br.readLine();
} catch (IOException e) {
// 处理异常
}
// 不需要 finally 块,资源会自动关闭
(七)常见异常示例
1. NullPointerException
String str = null;
System.out.println(str.length()); // 抛出 NullPointerException
2. ArrayIndexOutOfBoundsException
int[] arr = new int[5];
System.out.println(arr[10]); // 抛出 ArrayIndexOutOfBoundsException
3. ClassCastException
Object obj = "Hello";
Integer num = (Integer) obj; // 抛出 ClassCastException
4. NumberFormatException
String str = "abc";
int num = Integer.parseInt(str); // 抛出 NumberFormatException
(八)异常链
异常链允许将一个异常包装在另一个异常中,保留原始异常信息:
try {
// 代码
} catch (IOException e) {
throw new MyAppException("处理文件时出错", e); // 包装原始异常
}
(九)总结
Java 异常处理机制提供了强大的错误处理能力:
- try-catch-finally:基本的异常捕获和处理
- throws:声明方法可能抛出的异常
- throw:主动抛出异常
- 自定义异常:创建特定于应用的异常类型
- 最佳实践:具体异常、不忽略异常、正确释放资源
合理的异常处理可以提高程序的健壮性和可维护性。
