现代Java开发者需将测试与异常处理嵌入日常编码节奏:写代码顺手加断言,改逻辑前先看测试红不红,遇空值或IO失败立即思考“抛什么、谁捕、如何恢复”,通过JUnit 5参数化测试、Mock隔离、意图化命名、fail-fast模式强化测试,按受检/非受检分类处理异常,用失败复现、前置失败测试、覆盖率驱动补全防御,并借Maven、Checkstyle等工具固化规范。

现代 Java 开发者要真正把测试和异常处理用得扎实,关键不是堆概念,而是让这两项能力嵌入日常编码节奏里——写代码时顺手加断言,改逻辑前先看测试红不红,遇到空值或 IO 失败不硬扛,而是立刻想“这里该抛什么、谁来捕、怎么恢复”。下面从实操角度拆解怎么练。
用 JUnit 5 写“带呼吸感”的单元测试
别只写 @Test + assertEquals。现代测试要覆盖边界、验证行为、支持快速反馈:
- 用
@ParameterizedTest覆盖多种输入组合,比如测试一个金额格式化方法,同时喂入null、负数、超大数、含逗号字符串等 - 对涉及时间、随机数、外部依赖的代码,提前用
@ExtendWith(MockitoExtension.class)隔离,避免测试因系统时钟跳变或网络抖动失败 - 每个测试方法名用驼峰式表达意图,如
shouldReturnEmptyListWhenUserIdIsNegative(),比test1()更易维护 - 运行时开启
--fail-fast模式(Maven Surefire 插件可配),让第一个失败就停,省去翻几十个绿条找红点的时间
异常处理不靠 try-catch 堆砌,而靠分层归因
Java 异常不是“拦住报错就完事”,而是帮调用方理解问题本质。练习重点在判断和分类:
- 受检异常(如
IOException)强制你面对:文件真可能不存在、网络真可能断开——这时别用catch吞掉,而是向上声明throws或转为更业务化的自定义异常(如DocumentLoadFailureException) - 非受检异常(如
NullPointerException、IllegalArgumentException)多数是编程错误,应在方法入口用Objects.requireNonNull()或Preconditions.checkArgument()主动拦截,把问题暴露在开发阶段 - 避免
catch (Exception e)这种宽泛捕获;如果必须兜底,至少记录e.getClass().getSimpleName()和原始消息,方便后续区分是配置错、数据脏还是服务不可用
把测试和异常串联进真实开发流
单独练测试或异常容易脱节。建议用小闭环驱动成长:
立即学习“Java免费学习笔记(深入)”;
- 每次修复一个线上
NullPointerException,倒推补一个单元测试复现它,再改代码修复——这样既补了测试缺口,又强化了空值防御意识 - 开发新接口时,先写一组失败场景的测试(如参数为空、数据库查无结果、下游超时),再写主流程;这些失败测试就是你异常处理策略的验收标准
- 用 IDE 的 “Run with Coverage” 功能跑测试,重点关注 service 层和 controller 层的分支覆盖率;低于 70% 的方法,大概率存在未处理的异常路径或边界遗漏
用工具固化习惯,而不是靠记忆
人会忘,但配置不会。几个低成本但高回报的设置:
- Maven 项目中启用
maven-surefire-plugin的failIfNoTests,防止误删测试类后构建仍通过 - 在
checkstyle或sonarqube中启用规则:禁止printStackTrace()、禁止空catch块、要求日志中包含异常堆栈(log.error("xxx", e)而非log.error("xxx " + e)) - 用
Lombok的@SneakyThrows谨慎简化受检异常(仅限私有工具方法),但公开 API 必须显式声明或转换,保持契约清晰


















