Java·关于异常处理
一、概念
先讲一个文字意义上的表达:异常是程序运行时偏离预期逻辑的事件(如空指针、数组越界、文件不存在等),若不处理会导致程序终止。其作用是:将 “异常处理逻辑” 与 “正常业务逻辑” 分离,让代码更简洁、可维护。
二、例子
举个例子:就像咖啡店带点单流程
一般正常的点单流程是(即对程序而言所谓的”正常业务逻辑“):你走进咖啡店,告诉店员”要一杯拿铁“,店员制作咖啡,你付款,拿到咖啡后离开。这是预期内的顺畅流程,就像程序按代码顺序执行核心功能。
但是可能出现的情况是(即对应程序中的”异常“):①你说要一杯猫屎咖啡,但店里根本就没有这一款(程序”非法参数异常“);②你付款时发现手机余额不足(程序”业务逻辑异常“);③咖啡机故障,无法制作咖啡(程序”资源故障异常“)。
我们先来想象一下,如果没有”异常处理“的情况。当店员听到”猫屎咖啡“后愣住了,不知道该干嘛,整个点单系统直接停滞住了(程序直接崩溃,报错后直接停止运行)。
如果有了”异常处理“后:①店员立刻说 “抱歉,我们没有猫屎咖啡,推荐您美式或拿铁”(捕获异常,提示原因,引导用户修正);②你收到 “余额不足” 提示,选择刷信用卡或取消订单(捕获异常,提供替代方案,不中断点单流程);③店员说 “抱歉,咖啡机故障了,要么等 30 分钟,要么全额退款”(捕获严重异常,给出折中方案,优雅处理,不导致整个咖啡店 “瘫痪”)。
三、作用
即,有上面的例子可以引出关于”异常处理“的三个核心作用:①避免程序崩溃(就像咖啡机故障时,咖啡店不会关门,只是提供替代方案);②明确提示问题(让用户(或开发者)知道 “哪里错了”,而非不明所以);③分离处理逻辑(店员不用在 “正常制作咖啡” 的流程中反复纠结 “如果没这款咖啡怎么办”,而是遇到问题时调用专门的 “异常应对流程”(类似程序中 try 块写业务,catch 块写处理逻辑))。
一句话概括:异常不只是 “提前声明可能出问题”,还包括 “问题已经发生时,用预设逻辑处理它”,本质就是 “问题发生后,不崩溃,而是按提前准备好的方案应对”。
四、异常体系结构
在 Java 异常体系结构中,核心知识点可从体系层级、异常分类、处理机制、实践要点四个维度梳理:

1.体系层级(继承关系)
Java 所有异常的根类(即父类)是 java.lang.Throwable,它有两个直接子类:
- Error:JVM 层面的严重错误,程序无法处理(如
OutOfMemoryError内存溢出、StackOverflowError栈溢出)。 - Exception:程序可处理的异常,分为两类:
- RuntimeException(非受检异常 / 运行时异常):编译期不强制处理,运行时才会暴露(如
NullPointerException空指针、ArrayIndexOutOfBoundsException数组越界)。 - Checked Exception(受检异常):编译期强制要求处理(如
IOException文件操作异常、SQLException数据库异常),否则编译报错。
- RuntimeException(非受检异常 / 运行时异常):编译期不强制处理,运行时才会暴露(如
这里注意受检异常与非受检异常,其核心区别在于,编译期是否强制要求处理。
2.异常分类与典型示例

3.异常处理机制
try-catch-finally(捕获并处理)
- 语法:
try包裹可能抛异常的代码,catch按 “子异常在前、父异常在后” 捕获特定异常,finally无论是否异常都会执行(常用于关闭资源)。 - 示例:
try {// 可能抛异常的代码 } catch (NullPointerException e) {// 处理空指针 } catch (Exception e) {// 处理其他异常 } finally {// 关闭资源(如IO流) }
throws(声明异常)
- 方法声明时用
throws告知调用者 “此方法可能抛出某异常,需由调用者处理”。 - 示例:
public void readFile() throws IOException {// 可能抛IO异常的代码 }
throw(主动抛异常)
- 手动触发指定异常(常用于业务校验),需实例化异常对象。
- 示例:
if (age < 0) {throw new IllegalArgumentException("年龄不能为负"); }这里需要注意的是:throws和throw的区别:

try-with-resources(自动关闭资源)
- Java 7+ 特性,资源(实现
AutoCloseable接口,如FileInputStream)在try括号内声明,会自动关闭,无需手动在finally中处理。 - 示例:
try (FileInputStream fis = new FileInputStream("test.txt")) {// 操作文件 } catch (IOException e) {// 处理异常 }
4.自定义异常
- 场景:Java 内置异常无法满足业务需求时(如 “用户余额不足”)。
- 实现:继承
Exception(受检)或RuntimeException(非受检),并提供构造方法。 - 示例:
// 自定义受检异常 public class BalanceInsufficientException extends Exception {public BalanceInsufficientException(String message) {super(message);} }
5.最佳实践
- 避免捕获所有异常(
catch (Exception e)),需精准捕获特定异常。 - 异常信息要明确(如 “文件 xxx 不存在” 而非 “IO 异常”),便于排查。
- 资源操作(文件、数据库连接)优先用
try-with-resources自动关闭。 - 非受检异常用于编程错误(如空指针),受检异常用于外部依赖问题(如文件、网络)。
