知识点思维导图
21 个知识节点
Java(07) - 异常处理
读完后,你应能完成以下任务:
- 绘制“Java(07) - 异常处理 / try-catch(和 JS 基本一样)”的关键对象与数据流,解释“唯一区别:Java 的 catch 要声明捕获的异常类型 catch (Exception e),JS 不用。”,并用源码位置、日志或 Trace 标注证据。
- 为“Java(07) - 异常处理 / 抛异常:throw”设计正常与异常输入,验证“几乎一样,都是 throw new 异常对象(...)。”,输出首个偏差位置与回归测试结果。
- 实现“Java(07) - 异常处理 / demo 的自定义业务异常 BusinessException”的最小代码或配置,检验“意思是 BusinessException 是一种 RuntimeException,自动拥有父类的所有能力(如携带错误消息),再加上自己的扩展(错误码 code)。”,输出命令、结果与 Diff,并说明不适用边界。
try-catch 和 JS 几乎一样,重点是 Java 的"自定义业务异常"。用 demo 示例的 BusinessException 讲。
一、try-catch(和 JS 基本一样)
try {
// 可能出错的代码
int result = 10 / 0; // 除零会抛异常
} catch (Exception e) { // 注意要声明异常类型
e.printStackTrace(); // 打印错误堆栈
} finally {
// 无论是否出错都执行(清理资源等)
}
对比 JS:
try {
// ...
} catch (error) { // JS 不用声明类型
console.error(error)
} finally {
// ...
}
唯一区别:Java 的 catch 要声明捕获的异常类型 catch (Exception e),JS 不用。
二、抛异常:throw
// Java
throw new BusinessException("网点id不能为空");
// JS
throw new Error("网点id不能为空")
几乎一样,都是 throw new 异常对象(...)。
三、demo 的自定义业务异常 BusinessException
你在第 4 课 Service 代码里见过:
if (!CommonFunctions.meaningfulInt.test(id)) {
throw new BusinessException("网点id不能为空"); // ← 这个
}
它的示例定义(demo-common-core):
public class BusinessException extends RuntimeException { // ① 继承 RuntimeException
private Integer code = 1; // ② 错误码,默认 1
// ③ 多个构造方法(重载),支持不同的创建方式
public BusinessException(String message) {
super(message); // 调用父类构造,传错误消息
}
public BusinessException(int code, String message) {
super(message);
this.code = code; // 自定义错误码
}
public Integer getCode() {
return code;
}
}
3.1 逐点讲解
① extends RuntimeException —— 继承
这是你第一次见到继承。意思是 BusinessException 是一种 RuntimeException,自动拥有父类的所有能力(如携带错误消息),再加上自己的扩展(错误码 code)。
类比前端:
class BusinessError extends Error { // ES6 继承,概念一样
constructor(message) {
super(message)
}
}
② private Integer code = 1 —— 多带一个错误码
普通异常只有错误消息,demo 的业务异常额外带一个 code,前端可以根据 code 做不同处理。注意用 Integer(能为 null)而非 int。
③ 多个构造方法 —— 方法重载(Overload)
同一个类里,方法名相同、参数不同,叫重载。BusinessException 有好几个构造方法:
new BusinessException("消息") // 只传消息
new BusinessException(500, "消息") // 传错误码 + 消息
new BusinessException(throwable) // 传另一个异常
调用时根据你传的参数,自动匹配对应的构造方法。JS 没有重载(靠参数判断),Java 是语言原生支持。
四、为什么要自定义业务异常?
对比两种写法:
// ❌ 不好:直接返回错误字符串,调用方要自己判断
public String getOrganization(Integer id) {
if (id == null) return "错误:id为空";
// ... 正常逻辑也返回 String,调用方分不清是数据还是错误
}
// ✅ demo 的做法:抛业务异常,由统一的地方捕获处理
public OrganizationOut getOrganization(Integer id) {
if (id == null) {
throw new BusinessException("网点id不能为空"); // 直接中断,往上抛
}
// ... 下面只写正常逻辑,干净
}
好处:
- 正常逻辑和错误处理分离——方法体只写正常流程,出错就 throw,代码干净
- 统一处理——后端有个全局异常处理器,专门捕获
BusinessException,自动转成统一返回格式{ code, msg }给前端 - 错误码标准化——前端拿到 code 就知道是什么错
4.1 全局异常处理(概念)
后端通常有个 @ExceptionHandler 统一捕获异常:
// 伪代码示意:所有抛出的 BusinessException 都会被这里接住
@ExceptionHandler(BusinessException.class)
public R handleBusinessException(BusinessException e) {
return R.fail(e.getCode(), e.getMessage()); // 转成 { code, msg } 返回前端
}
所以 Service 里只管 throw,不用关心怎么返回给前端——这就是分层的好处。
五、检查型异常 vs 运行时异常(了解即可)
Java 异常分两类:
| 类型 | 说明 | 是否强制处理 |
|---|---|---|
| 运行时异常(RuntimeException) | 程序逻辑错误,如空指针、除零 | 不强制 try-catch |
| 检查型异常(Checked Exception) | 外部因素,如文件不存在、网络错误 | 编译器强制处理 |
BusinessException extends RuntimeException,属于运行时异常,所以调用方不强制 try-catch,可以一路往上抛到全局处理器。这是业务异常的常见设计。
六、常见异常类型
| 异常 | 什么时候出现 | JS 类比 |
|---|---|---|
NullPointerException |
调用 null 对象的方法(空指针) | Cannot read property of undefined |
ArrayIndexOutOfBoundsException |
数组越界 | 访问越界(JS 返回 undefined) |
NumberFormatException |
字符串转数字失败 | Number("abc") → NaN |
BusinessException |
demo 自定义的业务错误 | 自定义 Error |
最常踩的坑:空指针 NullPointerException。Java 对象可能是 null,调它的方法就崩。所以 demo 代码里到处是 Objects.isNull(x) 判空(第 4 课见过)。
七、本课小结
try-catch-finally和 JS 几乎一样,只是 catch 要声明类型throw new XxxException(...)抛异常,和 JS 一样- demo 用 BusinessException 表示业务错误,
extends RuntimeException(继承) - 方法重载:同名方法不同参数,Java 原生支持(JS 没有)
- 分层好处:Service 只管 throw,全局处理器统一转成
{ code, msg }返回前端 - 最常见的坑:空指针 NullPointerException,所以要勤判空
- 下一篇:注解与反射(Spring 框架的基础)
八、总结
- try-catch(和 JS 基本一样):唯一区别:Java 的 catch 要声明捕获的异常类型 catch (Exception e),JS 不用。
- 抛异常:throw:几乎一样,都是 throw new 异常对象(...)。
- demo 的自定义业务异常 BusinessException:意思是 BusinessException 是一种 RuntimeException,自动拥有父类的所有能力(如携带错误消息),再加上自己的扩展(错误码 code)。
- 为什么要自定义业务异常?:正常逻辑和错误处理分离——方法体只写正常流程,出错就 throw,代码干净 -> 统一处理——后端有个全局异常处理器,专门捕获 BusinessException,自动转成统一返回格式 { code, msg } 给前端 -> 错误码标准化——前端拿到 code 就知道是什么错
- 检查型异常 vs 运行时异常(了解即可):| 类型 | 说明 | 是否强制处理 |
- 常见异常类型:| NullPointerException | 调用 null 对象的方法(空指针) | Cannot read property of undefined |
学完自测
选择所有正确答案;提交后逐项核对判断依据。