本文目录导读:

我来详细介绍Java自定义异常的开发案例,从基础到进阶。
基础自定义异常
自定义受检异常(Checked Exception)
// 自定义受检异常类
public class InsufficientBalanceException extends Exception {
// 无参构造器
public InsufficientBalanceException() {
super();
}
// 带有异常信息的构造器
public InsufficientBalanceException(String message) {
super(message);
}
// 带有异常信息和原因的构造器
public InsufficientBalanceException(String message, Throwable cause) {
super(message, cause);
}
// 带有原因的构造器
public InsufficientBalanceException(Throwable cause) {
super(cause);
}
}
自定义非受检异常(Unchecked Exception)
// 自定义运行时异常
public class InvalidAccountException extends RuntimeException {
public InvalidAccountException() {
super();
}
public InvalidAccountException(String message) {
super(message);
}
public InvalidAccountException(String message, Throwable cause) {
super(message, cause);
}
}
实际业务案例:银行账户系统
完整的异常类定义
// 1. 账户相关异常基类
public class AccountException extends Exception {
private String errorCode;
public AccountException(String message, String errorCode) {
super(message);
this.errorCode = errorCode;
}
public String getErrorCode() {
return errorCode;
}
}
// 2. 余额不足异常
public class InsufficientBalanceException extends AccountException {
private double currentBalance;
private double requiredAmount;
public InsufficientBalanceException(double currentBalance, double requiredAmount) {
super(
String.format("余额不足!当前余额: %.2f, 需要: %.2f", currentBalance, requiredAmount),
"INSUFFICIENT_BALANCE"
);
this.currentBalance = currentBalance;
this.requiredAmount = requiredAmount;
}
public double getCurrentBalance() {
return currentBalance;
}
public double getRequiredAmount() {
return requiredAmount;
}
}
// 3. 账户锁定异常
public class AccountLockedException extends AccountException {
private String accountNumber;
private Date lockTime;
public AccountLockedException(String accountNumber, Date lockTime) {
super(
String.format("账户 %s 已被锁定,锁定时间: %s", accountNumber, lockTime),
"ACCOUNT_LOCKED"
);
this.accountNumber = accountNumber;
this.lockTime = lockTime;
}
public String getAccountNumber() {
return accountNumber;
}
public Date getLockTime() {
return lockTime;
}
}
// 4. 转账限额异常
public class TransferLimitExceededException extends AccountException {
private double transferAmount;
private double dailyLimit;
public TransferLimitExceededException(double transferAmount, double dailyLimit) {
super(
String.format("转账金额 %.2f 超过日限额 %.2f", transferAmount, dailyLimit),
"TRANSFER_LIMIT_EXCEEDED"
);
this.transferAmount = transferAmount;
this.dailyLimit = dailyLimit;
}
// 提供建议操作
public String getSuggestion() {
return "建议:请降低转账金额或联系客服提高限额";
}
}
业务逻辑实现
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class BankAccountService {
private Map<String, Account> accounts = new HashMap<>();
private Map<String, Double> dailyTransferAmount = new HashMap<>();
private static final double DAILY_TRANSFER_LIMIT = 50000.00;
// 初始化账户
public void createAccount(String accountNumber, double initialBalance) {
Account account = new Account(accountNumber, initialBalance);
accounts.put(accountNumber, account);
}
// 取款操作(演示受检异常)
public void withdraw(String accountNumber, double amount)
throws InsufficientBalanceException, AccountLockedException {
Account account = getAccount(accountNumber);
// 检查账户是否锁定
if (account.isLocked()) {
throw new AccountLockedException(accountNumber, account.getLockTime());
}
// 检查余额是否充足
if (account.getBalance() < amount) {
throw new InsufficientBalanceException(account.getBalance(), amount);
}
// 执行取款
account.setBalance(account.getBalance() - amount);
System.out.println("取款成功!当前余额: " + account.getBalance());
}
// 转账操作(演示多个异常处理)
public void transfer(String fromAccount, String toAccount, double amount)
throws InsufficientBalanceException, AccountLockedException,
TransferLimitExceededException {
// 检查转账限额
Double dailyTransfer = dailyTransferAmount.getOrDefault(fromAccount, 0.0);
if (dailyTransfer + amount > DAILY_TRANSFER_LIMIT) {
throw new TransferLimitExceededException(amount, DAILY_TRANSFER_LIMIT - dailyTransfer);
}
// 执行取款(可能抛出 InsufficientBalanceException 或 AccountLockedException)
withdraw(fromAccount, amount);
// 存入目标账户
Account target = getAccount(toAccount);
target.setBalance(target.getBalance() + amount);
// 更新日累计转账金额
dailyTransferAmount.put(fromAccount, dailyTransfer + amount);
System.out.println("转账成功!");
}
// 模拟账户操作(演示运行时异常)
public void processTransfer(String fromAccount, String toAccount, double amount) {
try {
transfer(fromAccount, toAccount, amount);
} catch (InsufficientBalanceException e) {
System.err.println("转账失败:" + e.getMessage());
System.err.println("当前余额: " + e.getCurrentBalance());
} catch (AccountLockedException e) {
System.err.println("转账失败:" + e.getMessage());
// 记录异常到日志
logError(e);
} catch (TransferLimitExceededException e) {
System.err.println("转账失败:" + e.getMessage());
System.err.println("建议:" + e.getSuggestion());
} catch (Exception e) {
System.err.println("未知错误:" + e.getMessage());
logError(e);
}
}
private Account getAccount(String accountNumber) {
Account account = accounts.get(accountNumber);
if (account == null) {
throw new InvalidAccountException("账户 " + accountNumber + " 不存在");
}
return account;
}
private void logError(Exception e) {
// 实际项目中这里会使用日志框架
System.err.println("错误时间: " + new Date());
System.err.println("错误类型: " + e.getClass().getName());
e.printStackTrace();
}
}
// 账户实体类
class Account {
private String accountNumber;
private double balance;
private boolean locked;
private Date lockTime;
public Account(String accountNumber, double balance) {
this.accountNumber = accountNumber;
this.balance = balance;
this.locked = false;
}
public String getAccountNumber() { return accountNumber; }
public double getBalance() { return balance; }
public void setBalance(double balance) { this.balance = balance; }
public boolean isLocked() { return locked; }
public void setLocked(boolean locked) {
this.locked = locked;
if (locked) {
this.lockTime = new Date();
}
}
public Date getLockTime() { return lockTime; }
}
测试代码
public class BankAccountTest {
public static void main(String[] args) {
BankAccountService bankService = new BankAccountService();
// 创建测试账户
bankService.createAccount("1001", 10000.00);
bankService.createAccount("1002", 5000.00);
System.out.println("=== 测试1: 正常取款 ===");
try {
bankService.withdraw("1001", 2000.00);
} catch (Exception e) {
System.err.println("取款异常:" + e.getMessage());
}
System.out.println("\n=== 测试2: 余额不足 ===");
try {
bankService.withdraw("1001", 90000.00);
} catch (InsufficientBalanceException e) {
System.err.println("取款失败:" + e.getMessage());
} catch (Exception e) {
System.err.println("其他异常:" + e.getMessage());
}
System.out.println("\n=== 测试3: 运行时异常 ===");
try {
bankService.processTransfer("1003", "1002", 1000.00);
} catch (Exception e) {
System.err.println("转账失败:" + e.getMessage());
}
System.out.println("\n=== 测试4: 复杂业务处理 ===");
bankService.processTransfer("1001", "1002", 3000.00);
System.out.println("\n=== 测试5: 转账超限 ===");
bankService.processTransfer("1001", "1002", 100000.00);
}
}
最佳实践建议
异常设计原则
public class ExceptionBestPractices {
// ✅ 正确:提供有意义的异常信息
public class UserNotFoundException extends RuntimeException {
public UserNotFoundException(String userId) {
super(String.format("用户 %s 不存在", userId));
}
}
// ❌ 错误:缺乏有意义的异常信息
public class UserNotFoundException extends RuntimeException {
public UserNotFoundException() {
super(); // 没有有用的信息
}
}
// ✅ 正确:包含错误码
public class BusinessException extends Exception {
private String errorCode;
public BusinessException(String message, String errorCode) {
super(message);
this.errorCode = errorCode;
}
}
// 异常处理的最佳实践方法
public void handleExceptionExample() {
try {
// 业务操作
riskyOperation();
} catch (SpecificException e) {
// ✅ 记录异常
logger.error("业务异常", e);
// ✅ 用户友好的错误信息
return errorResponse(e.getErrorCode(), e.getMessage());
} catch (Exception e) {
// ✅ 异常转换
throw new BusinessException("系统繁忙,请稍后重试", "SYSTEM_ERROR", e);
}
}
}
企业级应用中的扩展
// 统一的异常响应
public class ErrorResponse {
private String errorCode;
private String message;
private String timestamp;
private String path;
// getter/setter...
}
// 全局异常处理器
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(AccountException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ErrorResponse handleAccountException(AccountException e) {
return new ErrorResponse(
e.getErrorCode(),
e.getMessage(),
new Date().toString(),
// 获取当前请求路径
);
}
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ErrorResponse handleGenericException(Exception e) {
return new ErrorResponse(
"UNKNOWN_ERROR",
"系统繁忙,请稍后重试",
new Date().toString(),
""
);
}
}
这个案例覆盖了自定义异常的各个方面,包括:
- 不同类型的异常(受检/非受检)
- 丰富的异常信息
- 实际业务场景
- 异常处理的最佳实践
- 企业级应用扩展