1870 字
约 6 分钟
6
第46章 Java自定义异常
2026-09-24
无标签
第46章 Java自定义异常
面包屑导航 章节头部 学习目标
学习目标
- 掌握自定义异常类的创建方法和语法规则
- 理解检查型异常和非检查型异常的区别与选择
- 学会设计合理的异常继承层次结构
- 掌握异常链和异常包装技术的使用
- 了解异常处理的最佳实践和设计原则
- 学会在业务逻辑中合理使用自定义异常
自定义异常类型详解
自定义异常类型详解
在Java编程中,虽然标准库提供了丰富的异常类型,但在实际开发中,我们经常需要创建自定义异常来更准确地表达特定的错误情况。自定义异常能够提供更清晰的错误信息,便于问题定位和处理。
检查型异常(Checked Exception)
public class InvalidAgeException extends Exception {
private String errorCode;
public InvalidAgeException(String message, String errorCode) {
super(message);
this.errorCode = errorCode;
}
public String getErrorCode() {
return errorCode;
}
}
- 必须在方法签名中声明(throws)
- 必须被捕获处理或继续抛出
- 用于可预期的异常情况
- 强制调用者处理异常
非检查型异常(Unchecked Exception)
public class InsufficientFundsException extends RuntimeException {
private double currentBalance;
private double requestedAmount;
public InsufficientFundsException(String message,
double currentBalance, double requestedAmount) {
super(message);
this.currentBalance = currentBalance;
this.requestedAmount = requestedAmount;
}
}
- 不需要在方法签名中声明
- 可以选择性捕获处理
- 用于编程错误或运行时错误
- 不强制调用者处理
异常继承体系设计
异常继承体系设计
良好的异常继承体系能够提供清晰的异常分类,便于异常处理和维护。设计时应该根据业务领域和错误类型进行合理分层。
// 基础业务异常
abstract class BusinessLogicException extends Exception {
private String errorCode;
public BusinessLogicException(String message, String errorCode) {
super(message);
this.errorCode = errorCode;
}
public String getErrorCode() {
return errorCode;
}
}
// 订单相关异常
class InvalidOrderException extends BusinessLogicException {
public InvalidOrderException(String message, String errorCode) {
super(message, errorCode);
}
}
// 用户相关异常
class UserRegistrationException extends BusinessLogicException {
private String failureReason;
public UserRegistrationException(String message, String failureReason) {
super(message, "USER_REGISTRATION_FAILED");
this.failureReason = failureReason;
}
}
| 异常层级 | 说明 | 使用场景 |
|---|---|---|
| 基础异常类 | 定义通用的异常属性和方法 | 作为其他异常的父类,提供统一接口 |
| 领域异常类 | 按业务领域分类的异常 | 数据库异常、网络异常、业务异常等 |
| 具体异常类 | 特定错误情况的异常 | 用户不存在、余额不足、文件未找到等 |
异常链和异常包装
异常链和异常包装
异常链是一种重要的异常处理技术,它允许我们在抛出新异常时保留原始异常的信息,这对于问题诊断和调试非常有用。
public class ServiceException extends Exception {
public ServiceException(String message) {
super(message);
}
public ServiceException(String message, Throwable cause) {
super(message, cause);
}
}
public void businessMethod() throws ServiceException {
try {
// 调用底层方法
databaseOperation();
} catch (SQLException e) {
// 包装为业务异常,保留原始异常
throw new ServiceException("用户服务操作失败", e);
}
}
异常链的优势保留完整信息:不丢失原始异常的堆栈跟踪层次清晰:将底层技术异常转换为业务异常便于调试:可以追踪异常的完整传播路径封装实现:隐藏底层实现细节
完整代码示例
完整代码示例
以下是一个完整的自定义异常使用示例,展示了如何在实际项目中设计和使用自定义异常。
/**
* 自定义异常示例程序
* 演示如何创建和使用自定义异常类
*/
public class CustomExceptionExample {
public static void main(String[] args) {
CustomExceptionExample example = new CustomExceptionExample();
try {
// 测试年龄验证
example.validateAge(15);
} catch (InvalidAgeException e) {
System.out.println("捕获到自定义异常: " + e.getMessage());
System.out.println("错误代码: " + e.getErrorCode());
}
try {
// 测试银行账户操作
BankAccount account = new BankAccount("123456", 1000.0);
account.withdraw(1500.0);
} catch (InsufficientFundsException e) {
System.out.println("银行操作异常: " + e.getMessage());
System.out.println("当前余额: " + e.getCurrentBalance());
System.out.println("尝试提取: " + e.getRequestedAmount());
}
}
/**
* 验证年龄
*
* @param age 年龄
* @throws InvalidAgeException 当年龄无效时抛出
*/
public void validateAge(int age) throws InvalidAgeException {
if (age < 0) {
throw new InvalidAgeException("年龄不能为负数", "AGE_NEGATIVE");
}
if (age > 150) {
throw new InvalidAgeException("年龄不能超过150岁", "AGE_TOO_HIGH");
}
if (age < 18) {
throw new InvalidAgeException("年龄必须满18岁", "AGE_TOO_LOW");
}
System.out.println("年龄验证通过: " + age + "岁");
}
}
💻 查看完整代码 - 在线IDE体验 异常设计最佳实践
异常设计最佳实践
异常设计原则
推荐做法
// 明确的异常命名
InvalidEmailFormatException
DatabaseConnectionTimeoutException
InsufficientPermissionException
// 提供有用的错误信息
throw new InvalidAgeException(
String.format("年龄%d超出有效范围[0-150]", age),
"AGE_OUT_OF_RANGE"
);
// 保留异常链
try {
lowLevelOperation();
} catch (IOException e) {
throw new ServiceException("服务操作失败", e);
}
- 使用清晰描述性的异常名称
- 提供详细的错误信息和上下文
- 保留原始异常信息(异常链)
- 包含足够信息供调用者处理
应该避免
// 模糊的异常命名
MyException
BadException
ErrorException
// 丢失原始异常信息
try {
operation();
} catch (Exception e) {
throw new CustomException("操作失败"); // 丢失了原始异常
}
// 过度使用检查型异常
public void setAge(int age) throws InvalidAgeException // 过度
- 使用模糊或无意义的异常名称
- 丢失原始异常的堆栈信息
- 过度使用检查型异常
- 异常信息不够具体或有用
异常处理策略
异常处理策略
选择异常类型的指导原则检查型异常:用于可预期且调用者应该处理的错误情况非检查型异常:用于编程错误或不可恢复的运行时错误异常转换:将底层技术异常转换为业务异常快速失败:在发现错误时立即抛出异常
异常设计注意事项避免创建过多的异常类,保持合理的粒度异常类应该是不可变的,避免状态变化考虑异常的性能影响,避免在热点代码中频繁抛出为异常提供国际化支持,便于多语言环境文档化异常的使用场景和处理建议
本章小结
本章小结
- 自定义异常分为检查型异常(继承Exception)和非检查型异常(继承RuntimeException)
- 良好的异常继承体系能够提供清晰的异常分类和处理机制
- 异常链技术允许保留原始异常信息,便于问题诊断和调试
- 异常设计应该遵循明确命名、提供详细信息、保留异常链等原则
- 选择异常类型时要考虑错误的性质和调用者的处理能力
- 异常应该携带足够的上下文信息,便于问题定位和恢复
- 避免过度使用异常,保持代码的清晰性和性能
导航链接 上一章:throw和throws关键字 章节测试 下一章:异常处理最佳实践 JavaScript
评论
0 条
还没有评论,先写一条吧。