Skip to content

Java 异常处理笔记

一、什么是异常?

在程序运行过程中发生的不正常事件,会打断正常的执行流程,称为 异常(Exception)

Java 提供了一套完整的异常处理机制,让开发者可以优雅地处理错误情况,提高程序的健壮性和可读性。

二、Java 异常体系结构

Java 中所有的异常类都继承自 java.lang.Throwable 类,其主要子类如下:

Throwable
├── Error            // 严重问题,一般不处理(如 OutOfMemoryError)
└── Exception        // 程序中可以捕获和处理的问题
    ├── RuntimeException   // 非受检异常(Unchecked Exceptions)
    └── 其他异常           // 受检异常(Checked Exceptions)

常见异常分类:

类型示例是否必须处理
ErrorOutOfMemoryError, StackOverflowError❌ 不建议处理
RuntimeException 及其子类NullPointerException, ArrayIndexOutOfBoundsException❌ 不强制处理
其他 Exception 子类IOException, SQLException, ClassNotFoundException✅ 必须处理或声明抛出

三、异常处理的五种关键字

Java 提供了以下关键字来进行异常处理:

关键字作用
try包含可能会发生异常的代码块
catch捕获并处理异常
finally无论是否发生异常,都会执行的代码块(如关闭资源)
throw显式抛出一个异常对象
throws在方法声明中声明该方法可能抛出的异常类型

四、try-catch-finally 的使用

基本语法:

java
try {
    // 可能发生异常的代码
} catch (ExceptionType1 e1) {
    // 处理异常
} catch (ExceptionType2 e2) {
    // 处理另一种异常
} finally {
    // 总是执行的代码(如关闭文件、数据库连接等)
}

示例:

java
try {
    int result = 10 / 0;
} catch (ArithmeticException e) {
    System.out.println("除数不能为零");
} finally {
    System.out.println("finally 块总是执行");
}

输出:

除数不能为零
finally 块总是执行

五、多异常捕获(Java 7+)

你可以在一个 catch 块中捕获多个异常类型(用 | 分隔):

java
try {
    // ...
} catch (IOException | SQLException e) {
    e.printStackTrace();
}

六、throws 和 throw 的区别

对比项throwsthrow
位置写在方法签名上写在方法体内
作用声明该方法可能抛出哪些异常实际抛出一个异常对象
参数类型异常类名异常实例

示例:

java
public void readFile(String filename) throws IOException {
    if (filename == null) {
        throw new NullPointerException("文件名不能为空");
    }
    // ...
}

七、自定义异常

你可以通过继承 ExceptionRuntimeException 来创建自己的异常类。

示例:受检异常

java
class InvalidAgeException extends Exception {
    public InvalidAgeException(String message) {
        super(message); // 调用 Exception(message) 构造方法
    }
}

public class Person {
    public void setAge(int age) throws InvalidAgeException {
        if (age < 0) {
            throw new InvalidAgeException("年龄不能为负数");
        }
    }
}

示例:非受检异常

java
class InvalidNameException extends RuntimeException {
    public InvalidNameException(String message) {
        super(message); // 调用 RuntimeException(message) 构造方法
    }
}

public class Person {
    public void setName(String name) {
        if (name == null || name.isEmpty()) {
            throw new InvalidNameException("名字不能为空");
        }
    }
}

八、异常处理的最佳实践

原则说明
❌ 不要“吞”异常即不要写空的 catch
✅ 记录日志使用 e.printStackTrace() 或日志框架记录异常信息
✅ 资源清理放在 finally如关闭文件、网络连接等
✅ 尽量具体捕获异常不要用 catch (Exception e) 捕捉所有异常
✅ 抛出合适的异常根据业务逻辑选择受检/非受检异常
✅ 使用 try-with-resources(Java 7+)自动关闭资源,避免手动写 finally

示例:try-with-resources(自动关闭资源)

java
try (FileInputStream fis = new FileInputStream("file.txt")) {
    int data = fis.read();
    while (data != -1) {
        System.out.print((char) data);
        data = fis.read();
    }
} catch (IOException e) {
    e.printStackTrace();
}

等价于

java
FileInputStream fis = new FileInputStream("file.txt");
try {
    // ...
} finally {
    fis.close();
}

九、受检异常 vs 非受检异常(重要对比)

特征受检异常(Checked Exceptions)非受检异常(Unchecked Exceptions)
继承关系继承自 Exception,但不是 RuntimeException继承自 RuntimeException
是否强制处理✅ 是❌ 否
示例IOException, SQLExceptionNullPointerException, ArrayIndexOutOfBoundsException
推荐使用场景期望调用者处理的外部错误(如 IO、网络)编程错误或不可恢复的内部错误

十、总结一句话:

Java 的异常处理机制是一种强大的工具,帮助开发者识别和处理程序中的异常情况。理解 try-catch-finally 的使用、区分受检与非受检异常、合理使用 throwthrows,以及编写自定义异常,是写出高质量 Java 程序的关键技能。