本文目录导读:

我来系统地介绍Java异常处理的规范化流程和最佳实践。
异常处理的核心原则
异常分类
// Throwable 体系
Throwable
├── Error(不可处理,系统级错误)
│ ├── OutOfMemoryError
│ └── StackOverflowError
└── Exception(可处理)
├── Checked Exception(必须处理)
│ ├── IOException
│ ├── SQLException
│ └── ClassNotFoundException
└── Unchecked Exception(运行时异常)
├── NullPointerException
├── IllegalArgumentException
└── IndexOutOfBoundsException
标准异常处理模式
基础try-catch-finally
public class StandardExceptionHandling {
// 基本模式
public void basicHandling() {
try {
// 可能抛出异常的代码
riskyOperation();
} catch (SpecificException e) {
// 处理特定异常
log.error("特定异常发生", e);
throw new BusinessException("操作失败", e);
} catch (GeneralException e) {
// 处理通用异常
log.error("通用异常", e);
handleGracefully(e);
} finally {
// 清理资源(必须执行)
closeResources();
}
}
// Java 7+ try-with-resources
public void tryWithResources() {
try (Connection conn = getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM users")) {
while (rs.next()) {
processUser(rs);
}
} catch (SQLException e) {
log.error("数据库操作异常", e);
throw new DataAccessException("查询用户失败", e);
}
}
}
多层异常处理
public class MultiLayerExceptionHandling {
// Service层
public class UserService {
public User createUser(UserDTO dto) {
try {
validateUser(dto);
User user = convertToEntity(dto);
return userRepository.save(user);
} catch (ValidationException e) {
throw new BusinessException("用户数据验证失败", e);
} catch (DataAccessException e) {
throw new BusinessException("用户创建失败", e);
}
}
}
// Controller层
@RestController
public class UserController {
@PostMapping("/users")
public ResponseEntity<ApiResponse<User>> createUser(@RequestBody UserDTO dto) {
try {
User user = userService.createUser(dto);
return ResponseEntity.ok(ApiResponse.success(user));
} catch (BusinessException e) {
return ResponseEntity.badRequest()
.body(ApiResponse.error(e.getMessage()));
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(ApiResponse.error("系统异常"));
}
}
}
}
自定义异常体系
异常层次结构
// 基础业务异常
public abstract class BaseException extends RuntimeException {
private final String errorCode;
private final Object[] args;
public BaseException(String errorCode, String message, Object... args) {
super(message);
this.errorCode = errorCode;
this.args = args;
}
public BaseException(String errorCode, String message, Throwable cause) {
super(message, cause);
this.errorCode = errorCode;
this.args = new Object[0];
}
public String getErrorCode() {
return errorCode;
}
public Object[] getArgs() {
return args;
}
}
// 具体业务异常
public class UserNotFoundException extends BaseException {
public UserNotFoundException(Long userId) {
super("USER_001",
String.format("用户不存在: %d", userId),
userId);
}
}
public class InsufficientBalanceException extends BaseException {
public InsufficientBalanceException(Double balance, Double required) {
super("BALANCE_001",
String.format("余额不足: 当前%.2f, 需要%.2f", balance, required),
balance, required);
}
}
异常码枚举
public enum ErrorCode {
// 系统级错误
SYSTEM_ERROR("SYS_001", "系统异常"),
DATABASE_ERROR("SYS_002", "数据库异常"),
// 业务级错误
USER_NOT_FOUND("USER_001", "用户不存在"),
USER_ALREADY_EXISTS("USER_002", "用户已存在"),
INVALID_PARAMETER("PARAM_001", "参数验证失败"),
// 权限错误
UNAUTHORIZED("AUTH_001", "未授权"),
FORBIDDEN("AUTH_002", "无权限"),
TOKEN_EXPIRED("AUTH_003", "Token过期");
private final String code;
private final String message;
ErrorCode(String code, String message) {
this.code = code;
this.message = message;
}
public String getCode() { return code; }
public String getMessage() { return message; }
}
统一异常处理
Spring Boot全局异常处理
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(BusinessException.class)
public ResponseEntity<ErrorResponse> handleBusinessException(BusinessException e) {
ErrorResponse response = ErrorResponse.builder()
.code(e.getErrorCode())
.message(e.getMessage())
.timestamp(LocalDateTime.now())
.build();
return ResponseEntity.badRequest().body(response);
}
@ExceptionHandler(ValidationException.class)
public ResponseEntity<ErrorResponse> handleValidationException(ValidationException e) {
ErrorResponse response = ErrorResponse.builder()
.code("VALIDATION_ERROR")
.message("参数验证失败")
.errors(e.getErrors())
.timestamp(LocalDateTime.now())
.build();
return ResponseEntity.badRequest().body(response);
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleException(Exception e) {
log.error("未处理的异常", e);
ErrorResponse response = ErrorResponse.builder()
.code("SYSTEM_ERROR")
.message("系统异常,请联系管理员")
.timestamp(LocalDateTime.now())
.build();
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(response);
}
// 参数校验异常
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponse> handleValidationExceptions(
MethodArgumentNotValidException ex) {
List<String> errors = ex.getBindingResult()
.getFieldErrors()
.stream()
.map(error -> error.getField() + ": " + error.getDefaultMessage())
.collect(Collectors.toList());
ErrorResponse response = ErrorResponse.builder()
.code("VALIDATION_ERROR")
.message("参数验证失败")
.errors(errors)
.timestamp(LocalDateTime.now())
.build();
return ResponseEntity.badRequest().body(response);
}
}
@Builder
@Data
public class ErrorResponse {
private String code;
private String message;
private List<String> errors;
private LocalDateTime timestamp;
}
资源管理最佳实践
使用try-with-resources
public class ResourceManagement {
// 自动关闭资源
public void processFile(String path) {
try (FileInputStream fis = new FileInputStream(path);
BufferedReader reader = new BufferedReader(new InputStreamReader(fis))) {
String line;
while ((line = reader.readLine()) != null) {
processLine(line);
}
} catch (IOException e) {
log.error("文件处理异常", e);
throw new FileProcessingException("处理文件失败: " + path, e);
}
}
// 自定义资源
public class DatabaseResource implements AutoCloseable {
private Connection connection;
public DatabaseResource(Connection connection) {
this.connection = connection;
}
@Override
public void close() {
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
log.error("关闭数据库连接失败", e);
}
}
}
}
}
异常日志规范
统一的日志记录
public class ExceptionLogging {
private static final Logger log = LoggerFactory.getLogger(ExceptionLogging.class);
public void handleWithLogging() {
try {
riskyOperation();
} catch (BusinessException e) {
// 记录业务异常
log.warn("业务异常: code={}, message={}, args={}",
e.getErrorCode(), e.getMessage(), e.getArgs());
// 重新包装后抛出
throw new ServiceException("处理失败", e);
} catch (DataAccessException e) {
// 记录数据访问异常(包含堆栈信息)
log.error("数据访问异常: {}", e.getMessage(), e);
// 转换为业务异常
throw new ServiceException("数据操作失败", e);
} catch (Exception e) {
// 记录未知异常
log.error("未预期的异常", e);
// 抛出系统异常
throw new SystemException("系统异常", e);
}
}
// 异常信息记录工具
public static String buildErrorMessage(Exception e) {
StringBuilder sb = new StringBuilder();
sb.append("异常类型: ").append(e.getClass().getName());
sb.append(", 消息: ").append(e.getMessage());
if (e.getCause() != null) {
sb.append(", 原因: ").append(e.getCause().getMessage());
}
// 添加业务上下文
sb.append(", 时间: ").append(LocalDateTime.now());
sb.append(", 线程: ").append(Thread.currentThread().getName());
return sb.toString();
}
}
最佳实践总结
异常处理原则
public class ExceptionBestPractices {
// ✅ 正确:使用具体的异常类型
public void specificException() {
try {
processStream(inputStream);
} catch (IOException e) {
throw new BusinessException("流处理失败", e);
}
}
// ❌ 错误:捕获过于宽泛的异常
public void broadException() {
try {
processStream(inputStream);
} catch (Exception e) { // 太过宽泛
throw new BusinessException("处理失败", e);
}
}
// ✅ 正确:异常转换时保留原始异常
public void preserveCause() {
try {
databaseOperation();
} catch (SQLException e) {
throw new BusinessException("数据库操作失败", e); // 保留cause
}
}
// ❌ 错误:丢弃原始异常信息
public void loseCause() {
try {
databaseOperation();
} catch (SQLException e) {
throw new BusinessException("数据库操作失败"); // 丢失原始异常
}
}
}
异常处理检查清单
- [x] 是否使用了具体的异常类型?
- [x] 自定义异常是否继承自合适的父类?
- [x] 异常信息是否包含足够的上下文?
- [x] 是否保留了原始异常堆栈?
- [x] 资源是否正确关闭(try-with-resources)?
- [x] 是否避免在finally中抛出异常?
- [x] 异常日志是否包含关键信息?
- [x] 是否实现了统一异常处理?
这样的异常处理架构能够保证代码的健壮性、可维护性和可读性,同时提供了清晰的错误反馈给调用方。