简介
"用测试替换异常"是一种预防性编程的重构手法。通过预先执行状态检查来避免异常发生,将异常处理逻辑转换为正常的条件分支,提高代码可预测性和执行效率。
针对的症状(代码坏味道)
- 使用异常处理预期内的常规错误
- 频繁捕获可预见的异常类型
- 异常处理掩盖业务逻辑缺陷
用测试替换异常的详细步骤
- 识别异常捕获点
- 查找try-catch中的常规业务错误处理
- 确定可预测的错误触发条件
- 创建状态检查方法
- 将异常触发条件转换为布尔测试方法
- 确保检查方法的幂等性
- 重构处理逻辑
- 用if-check替换try-catch结构
- 将catch块转换为else分支
- 清理残留结构
- 移除不再需要的异常声明
- 简化方法返回类型
示例
重构前代码:
class CollectionUtils {
String getFirstElement(List<String> list) {
try {
return list.get(0);
} catch (IndexOutOfBoundsException e) {
return null;
}
}
}
重构步骤:
-
创建空集合检查方法:
private boolean isEmpty(List<String> list) { return list == null || list.isEmpty(); } -
重构获取逻辑:
class CollectionUtils { String getFirstElement(List<String> list) { if (isEmpty(list)) { return null; } return list.get(0); } }
练习
基础练习题
-
空指针防御改造
// 重构前 class StringParser { int parse(String value) { try { return Integer.parseInt(value); } catch (NumberFormatException e) { return -1; } } }
进阶练习题
-
复合状态测试
// 重构前 class DatabaseAccessor { Connection getConnection(String config) { try { return DriverManager.getConnection(config); } catch (SQLException e) { throw new RuntimeError("Connection failed"); } } }
综合拓展练习题
-
复杂业务状态验证
// 重构前 class PaymentProcessor { void process(Order order) { try { validateOrder(order); chargeCustomer(order); } catch (PaymentException e) { handleFailure(order, e); } } }
代码审查要点
-
优点:
- 提高代码执行效率
- 明确业务约束条件
- 增强代码可测试性
-
潜在问题:
- 保证检查方法与业务操作的原子性
- 避免重复状态检查
- 正确处理竞态条件