简介
"用预检查替换异常"是一种防御性编程的重构手法。通过在可能引发异常的场景前添加前置条件检查,将运行时异常转换为可控的逻辑分支,提高代码健壮性和可维护性。
针对的症状(代码坏味道)
- 使用异常处理正常业务流程控制
- 频繁try-catch基础验证逻辑
- 异常处理成本高于业务逻辑本身
用预检查替换异常的详细步骤
- 识别异常触发点
- 查找代码中可能抛出异常的敏感操作
- 分析异常触发的前置条件
- 创建验证方法
- 将异常触发条件提取为独立验证方法
- 确保验证方法的无副作用性
- 添加前置检查
- 在调用敏感操作前执行验证
- 使用验证结果控制流程
- 重构异常处理
- 将catch块转换为条件判断
- 移除不必要的try-catch结构
示例
重构前代码:
class AccountManager {
void transfer(Account from, Account to, double amount) {
try {
from.withdraw(amount);
to.deposit(amount);
} catch (InsufficientFundsException e) {
System.out.println("Transfer failed: " + e.getMessage());
}
}
}
重构步骤:
-
创建预检查方法:
private boolean canTransfer(Account from, double amount) { return from.getBalance() >= amount; } -
重构转账逻辑:
class AccountManager { void transfer(Account from, Account to, double amount) { if (!canTransfer(from, amount)) { System.out.println("Transfer failed: Insufficient funds"); return; } from.withdraw(amount); to.deposit(amount); } }
练习
基础练习题
-
简单参数预检查
// 重构前 class StringUtils { String safeSubstring(String s, int begin) { try { return s.substring(begin); } catch (IndexOutOfBoundsException e) { return ""; } } }
进阶练习题
-
复合条件检查
// 重构前 class FileConverter { void convert(File input, String format) { try { validateFormat(format); processConversion(input); } catch (InvalidFormatException | ConversionFailureException e) { log.error("Conversion failed", e); } } }
综合拓展练习题
-
复杂业务规则检查
// 重构前 class LoanService { void approveLoan(Application app) { try { checkCreditHistory(app); verifyCollateral(app); processApproval(app); } catch (LoanException e) { app.reject(e.getReason()); } } }
代码审查要点
-
优点:
- 减少异常处理开销
- 提前暴露业务规则问题
- 改善代码可读性
-
潜在问题:
- 确保预检查与业务逻辑原子性
- 避免重复验证逻辑
- 保持验证逻辑与业务逻辑同步