代码语言

知识点思维导图

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不能为空");  // 直接中断,往上抛
    }
    // ... 下面只写正常逻辑,干净
}

好处:

  1. 正常逻辑和错误处理分离——方法体只写正常流程,出错就 throw,代码干净
  2. 统一处理——后端有个全局异常处理器,专门捕获 BusinessException,自动转成统一返回格式 { code, msg } 给前端
  3. 错误码标准化——前端拿到 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 |

学完自测

选择所有正确答案;提交后逐项核对判断依据。

1在“异常处理”中,需要同时满足“try-catch(和 JS 基本一样)”与“抛异常:throw”。给定正文约束“Java 的 catch 要声明捕获的异常类型 catch (Exception e),JS 不用。”,哪些判断保持了原有处理机制?多选
2“异常处理”出现偏差:“在“异常处理 / demo 的自定义业务异常 BusinessException”中,即使不满足“它的示例定义(demo-common-core)”,结果与副作用仍会保持不变。”已成为实际行为。围绕“demo 的自定义业务异常 BusinessException”与“逐点讲解”,哪些判断能定位被改变的职责或边界?多选
3评审“异常处理”方案时,验收条件包含“1. 正常逻辑和错误处理分离——方法体只写正常流程,出错就 throw,代码干净”。关于“为什么要自定义业务异常?”与“全局异常处理(概念)”的哪些决策符合正文机制?多选