1870 字
约 6 分钟
11
Java自定义异常
无标签

第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

Java自定义异常
https://clxhxhhr.top/posts/2747/
作者
clxstart
发布于
2026-09-19
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。