返回首页面试题

面试必备:Java 异常体系全解析

2026年03月25日7 min read

面试必备:Java 异常体系全解析

异常体系全景图

Throwable (可抛出的)
    │
    ├── Error (错误)           ← 程序无法处理,编译器不检查
    │   ├── OutOfMemoryError
    │   ├── StackOverflowError
    │   ├── NoClassDefFoundError
    │   └── ...
    │
    └── Exception (异常)       ← 可以处理
        │
        ├── RuntimeException (运行时异常/Unchecked)
        │   ├── NullPointerException
        │   ├── IndexOutOfBoundsException
        │   ├── ClassCastException
        │   ├── ArithmeticException
        │   └── ...
        │
        └── 其他异常 (Checked) ← 编译器强制处理
            ├── IOException
            ├── SQLException
            ├── FileNotFoundException
            ├── ClassNotFoundException
            └── ...

Error vs Exception

Error(错误)

程序无法处理的严重问题,不需要捕获,也不应该捕获

// 常见的 Error
OutOfMemoryError      // 内存溢出
StackOverflowError    // 栈溢出
NoClassDefFoundError  // 类找不到
VirtualMachineError   // JVM 虚拟机错误

典型场景

// 递归没有终止条件,会 StackOverflowError
public void recursion() {
    recursion();  // 无限递归
}

Exception(异常)

程序可以处理的问题,需要捕获或声明抛出。


Checked vs Unchecked

这是面试的高频考点!

Checked Exception(受检异常)

编译器强制要求处理的异常。

// 必须 try-catch 或 throws
try {
    FileReader reader = new FileReader("file.txt");
} catch (FileNotFoundException e) {
    e.printStackTrace();
}

Unchecked Exception(运行时异常)

编译器不强制处理,属于程序逻辑错误。

// 不需要 try-catch,编译器不会报错
String s = null;
s.length();  // NullPointerException,但编译器不管

对比

特性CheckedUnchecked
编译器检查
必须处理
常见例子IOException, SQLExceptionNullPointerException
性质外部因素,环境可能出错程序 bug,逻辑错误

面试回答模板

"Checked Exception 是编译器强制处理的异常,表示外部因素导致的错误,比如 IO 操作、数据库访问。Unchecked Exception(运行时异常)是程序逻辑错误,比如空指针、数组越界,编译器不强制处理。"


异常处理语法

1. try-catch-finally

try {
    // 可能抛出异常的代码
    int result = 10 / 0;
} catch (ArithmeticException e) {
    // 捕获特定异常
    System.out.println("除数不能为0");
} catch (Exception e) {
    // 捕获其他异常(大的放后面)
    e.printStackTrace();
} finally {
    // 无论是否异常都执行
    System.out.println("清理资源");
}

2. try-with-resources(Java 7+)

自动关闭资源,不用写 finally:

// 传统写法
try {
    FileReader reader = new FileReader("file.txt");
    // ... 读取文件
} finally {
    reader.close();  // 容易忘记或出错
}

// try-with-resources(推荐)
try (FileReader reader = new FileReader("file.txt")) {
    // ... 读取文件
}  // 自动关闭,不用写 finally

3. throws vs throw

// throws:声明方法可能抛出的异常(方法签名的一部分)
public void readFile() throws IOException {
    // 方法内部不处理,让调用者处理
    FileReader reader = new FileReader("file.txt");
}

// throw:手动抛出异常
public void validate(int age) {
    if (age < 0) {
        throw new IllegalArgumentException("年龄不能为负数");
    }
}

异常链

保留原始异常信息:

try {
    // 业务逻辑
    doSomething();
} catch (IOException e) {
    // 包装成新的业务异常,保留原异常
    throw new BusinessException("处理失败", e);
}

常见面试问题

Q1:finally 和 return 的执行顺序?

public int test() {
    try {
        return 1;
    } finally {
        // return 会把返回值暂存,执行完 finally 再返回
        // 这里的修改不会影响返回值
        return 2;
    }
}
// 返回值:2

Q2:finally 一定会执行吗?

几乎一定,但有例外:

// 情况1:System.exit()
try {
    System.exit(0);
} finally {
    // 不会执行
}

// 情况2:线程被杀死
// 如果当前线程被 kill,finally 不会执行

Q3:为什么 finally 中不建议 return?

public int bad() {
    try {
        return 1;
    } finally {
        return 2;  // 掩盖了 try 中的异常!
    }
}

Q4:OOM 和 StackOverflowError 是 Error 还是 Exception?

两者都是 Error,不是 Exception。

  • OutOfMemoryError extends Error
  • StackOverflowError extends Error

最佳实践

1. 不要捕获 Throwable

// ❌ 不好
catch (Throwable t) {
    // 会捕获 Error,不应该捕获
}

// ✓ 推荐:只捕获能处理的异常
catch (IOException e) {
    // 处理 IO 错误
}

2. 不要吞掉异常

// ❌ 不好
catch (Exception e) {
    // 什么都不做,异常消失了
}

// ✓ 推荐:至少打印日志
catch (Exception e) {
    log.error("处理失败", e);
    throw e;  // 或者抛出
}

3. 异常要精确

// ❌ 不精确
catch (Exception e) { }

// ✓ 推荐:精确捕获
catch (FileNotFoundException e) { }
catch (IOException e) { }

4. 不要用异常做流程控制

// ❌ 不好:异常是用来处理意外情况的
try {
    for (int i = 0; ; i++) {
        arr[i] = i;
    }
} catch (ArrayIndexOutOfBoundsException e) {
    // 循环正常结束了
}

// ✓ 推荐:用正常判断
for (int i = 0; i < arr.length; i++) {
    arr[i] = i;
}

总结

异常体系:
├── Error(错误)→ 严重,不能处理
└── Exception(异常)→ 可处理
    ├── Checked(受检)→ 编译器强制处理
    └── Unchecked(运行时)→ 逻辑错误

关键点:

  1. Checked vs Unchecked 的区别和使用场景
  2. try-catch-finally 的执行顺序
  3. throws vs throw 的区别
  4. 不要吞掉异常,不要用异常做流程控制

评论区