銀行賬戶類 Bank 需支援存款、取款,並對異常情況拋出自定義檢查型異常:
InsufficientFundsException(餘額不足)NegativeFundsException(金額為負)// 餘額不足異常
public class InsufficientFundsException extends Exception {
private double amount;
private double balance;
public InsufficientFundsException(double amount, double balance) {
super(String.format("取款金額 %.2f 超過餘額 %.2f", amount, balance));
this.amount = amount;
this.balance = balance;
}
public double getAmount() { return amount; }
public double getBalance() { return balance; }
}
// 金額為負異常
public class NegativeFundsException extends Exception {
private double amount;
public NegativeFundsException(double amount) {
super(String.format("金額 %.2f 不能為負數", amount));
this.amount = amount;
}
public double getAmount() { return amount; }
}
關鍵點:繼承 Exception(檢查型異常),攜帶業務數據字段,構造器生成可讀訊息。
public class Bank {
private double balance;
public Bank(double initialBalance) {
if (initialBalance < 0) throw new IllegalArgumentException("初始餘額不能為負");
this.balance = initialBalance;
System.out.println("賬戶開戶成功,初始餘額:" + balance + " 元");
}
// 存款
public void deposit(double amount) throws NegativeFundsException {
if (amount < 0) throw new NegativeFundsException(amount);
balance += amount;
System.out.println("存款 +" + amount + ",當前餘額:" + balance);
}
// 取款
public void withdraw(double amount) throws InsufficientFundsException, NegativeFundsException {
if (amount < 0) throw new NegativeFundsException(amount);
if (amount > balance) throw new InsufficientFundsException(amount, balance);
balance -= amount;
System.out.println("取款 -" + amount + ",當前餘額:" + balance);
}
public double getBalance() { return balance; }
}
public class BankTest {
public static void main(String[] args) {
Bank account = new Bank(100.0);
// 1. 正常存取
try {
account.deposit(50);
account.withdraw(30);
} catch (Exception e) {
e.printStackTrace();
}
// 2. 取款金額為負
try {
account.withdraw(-15);
} catch (NegativeFundsException e) {
System.err.println("[業務異常] " + e.getMessage() + " | 金額=" + e.getAmount());
} catch (InsufficientFundsException e) {
System.err.println("[業務異常] " + e.getMessage());
}
// 3. 餘額不足
try {
account.withdraw(200);
} catch (InsufficientFundsException e) {
System.err.println("[業務異常] " + e.getMessage() + " | 申請=" + e.getAmount() + " 餘額=" + e.getBalance());
} catch (NegativeFundsException e) {
System.err.println("[業務異常] " + e.getMessage());
}
// 4. 存款金額為負
try {
account.deposit(-100);
} catch (NegativeFundsException e) {
System.err.println("[業務異常] " + e.getMessage());
}
System.out.println("最終餘額:" + account.getBalance() + " 元");
}
}
賬戶開戶成功,初始餘額:100.0 元 存款 +50.0,當前餘額:150.0 取款 -30.0,當前餘額:120.0 [業務異常] 金額 -15.00 不能為負數 | 金額=-15.0 [業務異常] 取款金額 200.00 超過餘額 120.00 | 申請=200.0 餘額=120.0 [業務異常] 金額 -100.00 不能為負數 | 金額=-100.0 最終餘額:120.0 元
| 原則 | 說明 |
|---|---|
| 業務異常用檢查型異常 | 強制調用者處理,API 契約明確 |
| 異常攜帶上下文數據 | amount、balance 等字段便於日誌、告警、補償邏輯 |
| 構造器生成人類可讀訊息 | 直接 e.getMessage() 即可記錄,無需額外拼裝 |
| 異常層次分類 | 可建立 BankException 基類,統一 catch |
| 避免吞噬異常 | 至少記錄日誌,或轉換為統一錯誤碼返回上層 |
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(InsufficientFundsException.class)
public R handleInsufficient(InsufficientFundsException e) {
return R.error("BALANCE_INSUFFICIENT", e.getMessage())
.put("requested", e.getAmount())
.put("available", e.getBalance());
}
@ExceptionHandler(NegativeFundsException.class)
public R handleNegative(NegativeFundsException e) {
return R.error("INVALID_AMOUNT", e.getMessage())
.put("amount", e.getAmount());
}
}
將自定義異常映射為統一 JSON 錯誤響應,前端可精準提示用戶。