Java 异常面试题 33 道

笔记/Java/面试专栏/Java 异常面试题 33 道

整理自 Java 异常面试题 33 道。详细原理见 Java 异常处理final、finally、finalize

相关学习笔记#

专题笔记
异常处理Java 异常处理
final/finally/finalizefinal、finally、finalize 区别

目录#


异常体系#

1. Java 异常简介#

异常是 Java 识别并响应错误的统一机制,让业务代码与错误处理分离。好的异常能回答:什么(类型)、在哪(堆栈)、为什么(消息)。

2. Throwable 体系#

Throwable 是根类,含 ErrorException 两大子类。

Error:JVM 级严重错误(OutOfMemoryErrorStackOverflowError),应用一般不捕获,也不应自定义 Error 子类。

Exception:程序可捕获处理。

  • RuntimeException(非受检):空指针、数组越界、类型转换、算术异常等;编译器不强制处理,应通过改代码避免
  • 其他 Exception(受检):IOExceptionClassNotFoundException 等;必须 try-catchthrows

3. 受检异常与非受检异常#

受检(checked)非受检(unchecked)
范围Exception 除 RuntimeException 及其子类RuntimeException + Error
编译器必须处理或声明不强制
语义可预期的、调用者应处理的失败编程错误或未检查的运行时问题

4. 异常关键字#

try 监听;catch 捕获;finally 收尾(常释放资源);throw 方法内抛出;throws 方法签名声明可能抛出的异常。


处理机制#

5. 声明异常(throws)#

知道如何处理的异常可捕获;不知道的继续向上 throws。受检异常必须处理或声明;Error、RuntimeException 不必用 throws 声明。

6. 抛出异常(throw)#

在方法内 throw new XxxException(),终止当前方法执行,交给调用栈处理。

7. 捕获异常(try-catch)#

运行期未知错误可在当前层 try-catch 处理,避免直接抛到最外层。

8. 如何选择异常类型#

能预检查规避的用 if(如 NPE);必须解析字符串数字才 catch NumberFormatException;业务失败用有语义的自定义异常。

9. 直接抛出 / 封装再抛出 / 捕获 / 自定义异常#

  • 不会处理 → throws 向上
  • 换异常类型对外暴露 → catchthrow new MyException(..., e) 保留 cause
  • 区分类型 → 多个 catchcatch (A | B e)
  • 自定义 → 通常提供无参 + 带 message 构造

10. try-catch-finally 与 try-with-resources#

finally 一般总会执行(用于关资源)。try-with-resources(Java 7+)自动关闭 AutoCloseable,若关闭时也抛异常,会抑制为 suppressed 异常。

11. Error 和 Exception 区别#

Error:虚拟机级,应用一般不捕获。Exception:应用可捕获处理,程序可继续或优雅失败。

12. 运行时异常和受检异常区别#

编译器是否强制处理;本质:是否强制调用者必须处理——强制则用受检,否则常用 RuntimeException。

13. JVM 如何处理异常#

方法抛异常 → 创建异常对象(含堆栈)→ 沿调用栈向上找处理器 → 找到则执行 catch → 找不到则由默认处理器处理并终止线程(打印堆栈)。

14. throw 和 throws 区别#

throwthrows
位置方法体内方法签名
数量一次抛一个可声明多个
类型受检/非受检均可声明可能抛出的类型

15. final、finally、finalize 区别#

final、finally、finalize 区别

  • final:类不可继承、方法不可重写、变量常量
  • finally:异常处理中必定执行的收尾块
  • finalize:Object 方法,GC 前清理(已不推荐依赖)

16. NoClassDefFoundError 和 ClassNotFoundException 区别#

NoClassDefFoundErrorClassNotFoundException
类型Error受检 Exception
时机运行时找不到类定义(编译时有,运行缺失)加载时找不到类(Class.forName 等)
处理不应捕获应捕获或声明

17. try-catch-finally 中哪个部分可以省略#

catch 可省略(仅 try-finally)。但仅 try 不能处理受检异常(编译不通过);try 适合只处理运行时异常或已声明 throws 的场景。

18. catch 中 return 了,finally 还会执行吗#

,在 return 之前执行 finally。注意:finally 中的 return覆盖 try/catch 的返回值;修改基本类型返回值在 finally 中往往无效(return 路径已绑定常量)。不要在 finally 中 return

19. ExampleA / ExampleB 捕获顺序#

ExampleB extends ExampleAthrow new ExampleB()catch (ExampleA e) 捕获,输出 ExampleA(多态,子类对象可被父类 catch 接住)。

20. 《Java 编程思想》异常题输出#

Caught Annoyance
Caught Sneeze
Hello World!

内层 catch Annoyance 后重新抛出,外层 catch Sneezefinally 仍执行。

21. 常见 RuntimeException#

NullPointerExceptionClassCastExceptionArrayIndexOutOfBoundsExceptionIndexOutOfBoundsExceptionArithmeticExceptionNumberFormatExceptionIllegalArgumentException 等。

22. Java 常见异常(节选)#

IllegalAccessErrorInstantiationErrorOutOfMemoryErrorStackOverflowErrorClassCastExceptionClassNotFoundExceptionArithmeticExceptionArrayIndexOutOfBoundsExceptionNullPointerExceptionNoSuchMethodException 等。


最佳实践与规约#

23. 在 finally 或 try-with-resources 中关闭资源#

不要在 try 末尾关流(异常时可能执行不到);用 finallytry-with-resources

24. 优先明确的异常类型#

NumberFormatException 而非笼统的 IllegalArgumentException;API 文档用 @throws 说明。

25. 使用描述性消息#

异常 message 简洁说明上下文,便于日志与排查。

26. 优先捕获最具体的异常#

catch (NumberFormatException) 放在 catch (IllegalArgumentException) 之前,否则子类块不可达。

27. 不要捕获 Throwable#

会连 Error 一起捕获,可能掩盖 OOM、StackOverflow 等严重问题。

28. 不要忽略异常#

空 catch 吞异常;至少打日志或重新抛出。

29. 不要记录后又抛出同一异常#

易重复日志;要么处理,要么抛;包装时用自定义异常并保留 cause。

30. 包装异常不要丢掉原始异常#

new MyException(msg, e)initCause(e),保留堆栈。

31. 不要用异常控制流程#

异常比 if 慢,应用条件分支处理正常分支。

32. 优先使用标准异常#

能满足需求就用 JDK 已有异常,再考虑自定义 XxxException

33. 阿里巴巴 Java 开发手册(异常节选)#

  • NPE、数组越界等应用 if 预检查,不要靠 catch
  • 异常不做流程控制;区分稳定/非稳定代码
  • 捕获就要处理,最外层转化为用户可理解提示
  • finally 关闭资源;禁止 finally 中 return
  • 捕获类型与抛出类型匹配;RPC/反射场景可用 Throwable 拦截 NoSuchMethodError
  • 推荐业务自定义异常,避免裸抛 Exception
  • 对外 API 用错误码,内部可用异常;跨应用 RPC 可考虑 Result 封装
文章目录

文章目录