一、引言:为何异常处理如此重要?
在任何一门编程语言中,异常处理都是保证程序健壮性和可维护性的关键机制。在 Java 中,异常机制不仅是错误检测工具,更是一种结构化的编程思维方式。
核心问题:
- 什么是异常?Java 中有哪些类型?
 - 如何正确抛出和捕获异常?
 - 如何设计自定义异常?
 - 异常链、finally 机制、try-with-resources 如何运作?
 
本文将带你系统梳理 Java 的异常体系与使用方法,并配合大量代码实例与图示,掌握异常处理的精髓。
二、Java 异常的层级结构图
+---------------------+
            |     Throwable       |
            +---------------------+
               /            \
      +--------+          +--------+
      |  Error |          | Exception |
      +--------+          +--------+
                             /       \
                 +----------+         +------------+
                 | Checked Exception | Unchecked (Runtime) |
                 +-------------------+----------------------+✅ 说明:
- Throwable:所有可抛出的类的顶层父类。
 - Error:严重错误(如内存溢出)不能被程序处理。
 - Exception:可恢复问题,程序应捕获和处理。
 
三、异常分类与示例
3.1 Checked Exception(受检异常)
编译器强制处理(try-catch 或 throws)
public void readFile() throws IOException {
    BufferedReader reader = new BufferedReader(new FileReader("file.txt"));
}常见类:
IOExceptionSQLExceptionParseException
3.2 Unchecked Exception(运行时异常)
编译器不会强制处理,但应当避免
int[] arr = new int[3];
System.out.println(arr[10]); // ArrayIndexOutOfBoundsException常见类:
NullPointerExceptionArithmeticExceptionArrayIndexOutOfBoundsException
四、try-catch-finally 使用详解
4.1 基本语法
try {
    int x = 10 / 0;
} catch (ArithmeticException e) {
    System.out.println("除以零错误:" + e.getMessage());
} finally {
    System.out.println("无论是否异常都会执行");
}4.2 多 catch 块处理
try {
    String s = null;
    s.length();
} catch (NullPointerException e) {
    System.out.println("空指针异常");
} catch (Exception e) {
    System.out.println("其他异常");
}💡 多个 catch 从具体到通用排列。
五、异常信息查看与日志记录
5.1 使用 e.printStackTrace() 打印堆栈信息
try {
    FileInputStream fis = new FileInputStream("non_exist.txt");
} catch (IOException e) {
    e.printStackTrace(); // 方便调试和定位
}5.2 使用日志记录异常
Logger logger = Logger.getLogger(MyClass.class.getName());
try {
    int[] nums = new int[5];
    nums[10] = 1;
} catch (Exception e) {
    logger.log(Level.SEVERE, "数组越界异常", e);
}六、自定义异常类
6.1 定义一个业务异常
public class MyBusinessException extends Exception {
    public MyBusinessException(String message) {
        super(message);
    }
}6.2 抛出自定义异常
public void checkAge(int age) throws MyBusinessException {
    if (age < 18) {
        throw new MyBusinessException("年龄不能小于18岁!");
    }
}七、异常链:保留原始异常信息
try {
    throw new IOException("IO错误");
} catch (IOException e) {
    throw new RuntimeException("封装异常", e);
}获取原始异常
catch (RuntimeException e) {
    Throwable cause = e.getCause(); // 原始 IOException
}八、try-with-resources 自动关闭资源(Java 7+)
自动调用 close(),无需手动写 finally
try (BufferedReader reader = new BufferedReader(new FileReader("data.txt"))) {
    System.out.println(reader.readLine());
} catch (IOException e) {
    e.printStackTrace();
}原理:
AutoCloseable 接口:
public interface AutoCloseable {
    void close() throws Exception;
}九、最佳实践建议
场景  | 推荐做法  | 
不可恢复异常(如内存)  | 不处理,允许程序中止  | 
业务逻辑错误  | 定义业务异常类,抛出并由调用者处理  | 
重复代码抛异常  | 封装到工具类或统一异常处理模块  | 
打印异常信息  | 使用日志框架(如 Log4j、SLF4J)  | 
流资源关闭  | 使用 try-with-resources  | 
十、实战案例:学生信息系统中的异常处理
10.1 场景需求
- 如果学生年龄 < 0,抛出异常
 - 如果学生文件不存在,捕获并提示
 - 所有异常需统一记录到日志
 
class StudentException extends Exception {
    public StudentException(String message) {
        super(message);
    }
}10.2 应用示例
public void addStudent(String name, int age) throws StudentException {
    if (age < 0) {
        throw new StudentException("年龄不能为负数");
    }
    // 其他逻辑
}10.3 日志捕获所有异常
try {
    addStudent("Tom", -5);
} catch (StudentException e) {
    logger.log(Level.SEVERE, e.getMessage(), e);
}十一、常见错误与误区
错误写法  | 问题说明  | 改进建议  | 
catch 块为空  | 捕获了异常却没有任何处理  | 至少记录或提示  | 
捕获 Exception 却处理不当  | 容易隐藏真实问题  | 尽量捕获具体异常类型  | 
try-catch 滥用(如普通业务流程)  | 可读性差,逻辑混乱  | 逻辑分离,用 return/if 替代  | 
finally 中使用 return  | 可能覆盖前面的异常  | 避免在 finally 中使用 return  | 
十二、小练习题
- 编写一个函数,传入一个文件路径,读取文件内容并打印,若文件不存在抛出异常。
 - 自定义一个异常 
PasswordTooShortException,判断密码长度不足时抛出。 - 模拟学生注册系统,姓名为空或年龄非法抛出异常。
 - 使用 try-with-resources 读取文件并打印首行。
 - 使用异常链封装多个异常信息,打印完整堆栈。
 
十三、图示复习:异常流程图
[方法执行]
      ↓
[出现错误]
      ↓
try 捕获异常?
  ↓        ↓
是         否
↓           ↓
catch 处理   异常向上传递
      ↓
  finally 执行(总是执行)
      ↓
  程序继续运行或中止十四、总结
Java 的异常机制并非只是“处理错误”的工具,它是一种设计思维,强调清晰分工、可预测行为和稳定程序结构。
通过本篇内容,你已经了解并掌握了:
✅ 异常层级、分类与使用场景
✅ try-catch-finally 和 try-with-resources 写法
✅ 自定义异常与异常链封装
✅ 日志记录、错误提示的标准做法
✅ 实战案例与最佳实践










