为什么 assertThrows 需要 () ->:Lambda 延迟执行与异常捕获

下面这段代码用来检查:用户名为空时,createUser 是否会抛出 IllegalArgumentException。

erlang 复制代码
assertThrows(
        IllegalArgumentException.class,
        () -> service.createUser("")
);

比较容易让人困惑的是第二个参数。既然真正要测试的是 service.createUser(""),为什么还要在外面套一层 () ->?

原因和 Java 计算方法参数的顺序有关。

直接调用会发生什么

如果去掉 Lambda,代码会变成这样:

arduino 复制代码
assertThrows(
        IllegalArgumentException.class,
        service.createUser("")
);

Java 在进入 assertThrows 之前,必须先算出两个参数的值。

第一个参数 IllegalArgumentException.class 没什么问题。计算第二个参数时,Java 会立刻调用 service.createUser("")。而这个方法收到空用户名后会抛出异常:

arduino 复制代码
throw new IllegalArgumentException("username cannot be blank");

这时 assertThrows 还没有开始执行,自然也没有机会捕获异常。

不过实际写代码时,更可能先遇到编译错误。assertThrows 的第二个参数需要一个 Executable,也就是"可执行的代码"。直接调用 createUser 得到的是返回值,不是 Executable,类型对不上。

() -> 把调用留到了后面

rust 复制代码
() -> service.createUser("")

这行代码没有调用 createUser。它创建了一个 Lambda,内容是"执行 service.createUser("")"。

可以先给它取个名字:

ini 复制代码
Executable task = () -> service.createUser("");

此时只是创建了 task。只有调用 task.execute(),里面的 createUser 才会运行。

assertThrows 拿到这个任务后,会在自己的异常捕获逻辑中执行它。内部过程可以粗略理解成:

php 复制代码
try {
    task.execute();
} catch (Throwable e) {
    // 检查异常类型是否符合预期
}

这样顺序就对了:assertThrows 先开始运行并准备捕获异常,然后执行 Lambda,最后检查 createUser 抛出的异常是不是 IllegalArgumentException。

因此,Lambda 传给 assertThrows 的不是异常,也不是方法运行后的结果,而是那段可能抛出异常的代码。

方法调用和 Lambda 的区别

service.createUser("") 表示现在调用方法。

() -> service.createUser("") 表示先保存这段调用,等 Lambda 被执行时再调用方法。

这也是 Lambda 很常见的一种用途:把一段行为交给其他代码,由接收方决定执行时机。按钮点击事件、线程任务和 Stream API 都会用到相同的思路。

还有一个容易混淆的地方:throw 不一定会终止整个程序。异常抛出后,Java 会沿着调用栈寻找能够处理它的 catch。assertThrows 正是利用这一点捕获异常,再判断异常类型是否符合测试要求。

这段代码的执行顺序可以压缩成一句话:

先进入 assertThrows,再执行 createUser,这样抛出的异常才在它的捕获范围内。

相关推荐
AI你一生一世3 小时前
不止于时序存储:DolphinDB 如何成为 AI 时代的工业智能底座
java·人工智能·struts·时序数据库·工业智能·dolphindb·ai基础设施
云-缩影3 小时前
拆解 AI 图像生成应用的后端架构:ECS、OSS 和大模型 API 怎么配合
java·spring boot·后端
瑞克-桑切斯4 小时前
7、MySQL 慢查询排查与优化实战指南
java·服务器·数据库
海的透彻8 小时前
dockerfile如何快速构建容器(java服务)
java·开发语言
code2cat8 小时前
Java工具篇之Gradle:用任务图组织构建与交付
java·开发语言·单元测试·gradle
后台模板学习9 小时前
大模型 Prompt 工程在电商订单系统中的踩坑记录
java·python·prompt
w_zero_one9 小时前
算法--构造
java·数据结构·算法
SL_staff9 小时前
制造业订单交付崩盘?用四层协同框架重建交付可信度(技术实践)
java·产品·全栈
SL_staff10 小时前
打破风控迭代死循环:用决策编排重构业务与技术协作链路
java·产品·全栈
Mikko711 小时前
Redis 连接数满了服务端有错误信息吗?连接数不增加却命令超时?6.2 实测连接池、超时与大 key 怎么判定
java·spring boot·redis·后端