第一部分:Java异常体系回顾

理解异常继承结构,为自定义异常打下基础

学习目标

掌握Java异常体系结构,区分受检异常和非受检异常

异常类层次结构

Throwable ├── Error (严重错误,程序不应处理) └── Exception ├── RuntimeException (非受检异常) └── 其他Exception子类 (受检异常)

异常分类

  • 受检异常(Checked):必须处理或声明
  • 非受检异常(Unchecked):RuntimeException及其子类
  • Error:JVM相关问题,通常不处理

第二部分:为什么需要自定义异常

了解自定义异常的业务价值和应用场景

使用场景

  • 业务规则违反(如余额不足)
  • 特定领域错误(如用户不存在)
  • 需要额外信息的异常
  • 区分系统异常和业务异常

优势

  • 提高代码可读性
  • 精确的错误处理
  • 便于日志记录和调试
  • 支持国际化错误消息

第三部分:创建受检异常类

继承Exception创建必须处理的异常类型

1

创建基础自定义异常

创建一个简单的受检异常,继承Exception类:

public class BusinessException extends Exception { public BusinessException() { super(); } public BusinessException(String message) { super(message); } public BusinessException(String message, Throwable cause) { super(message, cause); } }

必须提供所有四个标准构造方法

2

添加额外字段

为异常添加错误代码等额外信息:

public class UserNotFoundException extends Exception { private final String userId; private final int errorCode; public UserNotFoundException(String userId) { super("用户不存在: " + userId); this.userId = userId; this.errorCode = 404; } public String getUserId() { return userId; } public int getErrorCode() { return errorCode; } }
3

使用自定义异常

在服务类中使用自定义异常:

public class UserService { public User findUser(String userId) throws UserNotFoundException { if (userId == null || userId.trim().isEmpty()) { throw new UserNotFoundException(userId); } // 模拟数据库查找 User user = database.findById(userId); if (user == null) { throw new UserNotFoundException(userId); } return user; } }

第四部分:创建非受检异常类

继承RuntimeException创建无需强制处理的异常

1

创建运行时异常

继承RuntimeException创建非受检异常:

public class ValidationException extends RuntimeException { private final String field; private final Object value; public ValidationException(String field, Object value) { super(String.format("字段 '%s' 的值 '%s' 无效", field, value)); this.field = field; this.value = value; } public String getField() { return field; } public Object getValue() { return value; } }
2

使用场景示例

在参数验证中使用非受检异常:

public class UserValidator { public void validateEmail(String email) { if (email == null || !email.contains("@")) { throw new ValidationException("email", email); } } public void validateAge(int age) { if (age < 0 || age > 150) { throw new ValidationException("age", age); } } }

第五部分:自定义异常最佳实践

遵循行业标准,编写高质量的异常类

命名规范

  • 以"Exception"结尾
  • 使用描述性名称(如InvalidOrderStateException)
  • 避免使用过于通用的名称
  • 与业务领域保持一致

设计原则

  • 提供所有四个标准构造方法
  • 添加有用的额外信息
  • 使异常不可变(final字段)
  • 考虑序列化支持

高级技巧

使用异常链保留原始异常信息:

try { // 数据库操作 } catch (SQLException e) { throw new DataAccessException("数据库访问失败", e); }

第六部分:常见错误与解决方案

避免开发中的典型陷阱

错误1:过度使用受检异常

错误示例:

// 错误:为业务校验使用受检异常 public void validateUser(User user) throws InvalidUserException { if (user.getAge() < 18) { throw new InvalidUserException("用户未满18岁"); } }

解决方案:使用非受检异常

错误2:丢失异常信息

错误示例:

// 错误:丢失了原始异常信息 try { // 操作 } catch (Exception e) { throw new BusinessException("操作失败"); // 丢失了原始异常 }

正确做法:

throw new BusinessException("操作失败", e);

错误3:异常过于具体

错误示例:

// 过度设计:为每个验证规则创建单独异常 public class EmailTooShortException extends ValidationException {} public class EmailNoAtSignException extends ValidationException {}

解决方案:使用带有错误代码的统一异常

第七部分:完整实战案例

从零开始构建一个订单处理的异常体系

1

定义基础异常

public abstract class OrderException extends Exception { private final String orderId; protected OrderException(String orderId, String message) { super(message); this.orderId = orderId; } public String getOrderId() { return orderId; } }
2

创建具体异常类

public class OrderNotFoundException extends OrderException { public OrderNotFoundException(String orderId) { super(orderId, "订单不存在: " + orderId); } } public class InsufficientStockException extends OrderException { private final String productId; private final int requested; private final int available; public InsufficientStockException(String orderId, String productId, int requested, int available) { super(orderId, String.format( "商品 %s 库存不足,需求: %d,可用: %d", productId, requested, available)); this.productId = productId; this.requested = requested; this.available = available; } // getters... }
3

实现订单服务

public class OrderService { public void processOrder(String orderId) throws OrderException { Order order = findOrder(orderId); validateOrder(order); checkInventory(order); // 处理订单... } private Order findOrder(String orderId) throws OrderNotFoundException { Order order = orderRepository.findById(orderId); if (order == null) { throw new OrderNotFoundException(orderId); } return order; } private void checkInventory(Order order) throws InsufficientStockException { for (OrderItem item : order.getItems()) { int available = inventoryService.getStock(item.getProductId()); if (available < item.getQuantity()) { throw new InsufficientStockException( order.getId(), item.getProductId(), item.getQuantity(), available); } } } }

动手练习

  • 为一个银行系统创建自定义异常:InsufficientFundsException
  • 添加账户ID、当前余额、提款金额等字段
  • 实现转账方法,使用这个异常
  • 创建全局异常处理器
  • 添加单元测试验证异常行为

知识总结

回顾自定义异常的核心要点

关键概念

  • 受检异常 vs 非受检异常
  • 异常链的重要性
  • 异常信息的丰富性
  • 异常类的设计模式

检查清单

  • ✅ 异常类命名规范
  • ✅ 提供完整构造方法
  • ✅ 添加有用的额外信息
  • ✅ 正确使用异常链
  • ✅ 文档化异常使用场景