Java异常处理与全局异常处理全面指南

Java异常处理与全局异常处理全面指南

一、Java异常处理基础

1. 异常分类

Java中的异常分为两大类:

  • Checked Exception(检查型异常):必须被捕获或声明抛出,如IOException、SQLException
  • Unchecked Exception(非检查型异常):RuntimeException及其子类,如NullPointerException、ArrayIndexOutOfBoundsException

2. 基本异常处理语法

try {
    // 可能抛出异常的代码
} catch (SpecificException e) {
    // 处理特定异常
} catch (GeneralException e) {
    // 处理更一般的异常
} finally {
    // 无论是否发生异常都会执行的代码
}

3. 异常处理最佳实践

  1. 不要忽略异常:空的catch块是"罪恶"的
  2. 优先处理最具体的异常
  3. 合理使用finally释放资源
  4. 考虑使用try-with-resources(Java 7+)
  5. 避免在finally块中使用return

二、Spring全局异常处理机制

1. @ControllerAdvice + @ExceptionHandler

@ControllerAdvice
public class GlobalExceptionHandler {
    
    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleAllExceptions(Exception ex) {
        ErrorResponse error = new ErrorResponse(
            "SERVER_ERROR", 
            "An unexpected error occurred",
            HttpStatus.INTERNAL_SERVER_ERROR.value()
        );
        return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
    }
    
    @ExceptionHandler(ResourceNotFoundException.class)
    public ResponseEntity<ErrorResponse> handleResourceNotFound(
        ResourceNotFoundException ex) {
        ErrorResponse error = new ErrorResponse(
            "NOT_FOUND", 
            ex.getMessage(),
            HttpStatus.NOT_FOUND.value()
        );
        return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
    }
}

2. 自定义异常类

public class BusinessException extends RuntimeException {
    private String errorCode;
    private HttpStatus httpStatus;
    
    public BusinessException(String message, String errorCode, HttpStatus httpStatus) {
        super(message);
        this.errorCode = errorCode;
        this.httpStatus = httpStatus;
    }
    
    // getters
}

3. 统一响应格式

@Data
@AllArgsConstructor
@NoArgsConstructor
public class ErrorResponse {
    private String errorCode;
    private String message;
    private int status;
    private long timestamp;
    private String path;
    private List<ValidationError> validationErrors;
    
    public ErrorResponse(String errorCode, String message, int status) {
        this.errorCode = errorCode;
        this.message = message;
        this.status = status;
        this.timestamp = System.currentTimeMillis();
    }
}

@Data
@AllArgsConstructor
public class ValidationError {
    private String field;
    private String message;
}

三、高级异常处理技巧

1. 处理验证异常(Validation)

@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponse> handleValidationExceptions(
    MethodArgumentNotValidException ex) {
    
    List<ValidationError> errors = ex.getBindingResult()
        .getFieldErrors()
        .stream()
        .map(error -> new ValidationError(
            error.getField(), 
            error.getDefaultMessage()))
        .collect(Collectors.toList());
    
    ErrorResponse error = new ErrorResponse(
        "VALIDATION_FAILED",
        "Validation failed for one or more fields",
        HttpStatus.BAD_REQUEST.value(),
        errors
    );
    
    return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
}

2. 国际化异常消息

@ExceptionHandler(BusinessException.class)
public ResponseEntity<ErrorResponse> handleBusinessException(
    BusinessException ex, 
    WebRequest request,
    Locale locale) {
    
    String message = messageSource.getMessage(
        ex.getMessageKey(), 
        ex.getArgs(), 
        locale);
    
    ErrorResponse error = new ErrorResponse(
        ex.getErrorCode(),
        message,
        ex.getHttpStatus().value()
    );
    
    return new ResponseEntity<>(error, ex.getHttpStatus());
}

3. 日志记录策略

@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleAllExceptions(Exception ex, WebRequest request) {
    logger.error("Unexpected error occurred: {}", ex.getMessage(), ex);
    
    ErrorResponse error = new ErrorResponse(
        "SERVER_ERROR",
        "An unexpected error occurred",
        HttpStatus.INTERNAL_SERVER_ERROR.value(),
        request.getDescription(false)
    );
    
    return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
}

四、实战建议

  1. 分层异常处理

    • 控制器层:处理HTTP相关异常
    • 服务层:处理业务逻辑异常
    • 数据访问层:处理数据相关异常
  2. 异常转换:将底层异常转换为上层业务异常

  3. 异常信息设计

    • 包含足够的信息用于调试
    • 不暴露敏感信息
    • 提供明确的错误代码
  4. 监控与报警:对关键异常设置监控报警

  5. 文档化:为API消费者提供清晰的错误代码和含义文档

五、常见问题解决方案

  1. 处理404错误
@ControllerAdvice
public class CustomErrorController implements ErrorController {
    
    @RequestMapping("/error")
    public ResponseEntity<ErrorResponse> handleError(HttpServletRequest request) {
        Integer status = (Integer) request.getAttribute("javax.servlet.error.status_code");
        Exception exception = (Exception) request.getAttribute("javax.servlet.error.exception");
        
        ErrorResponse error = new ErrorResponse(
            "NOT_FOUND",
            "Requested resource not found",
            status
        );
        
        return new ResponseEntity<>(error, HttpStatus.valueOf(status));
    }
}
  1. 处理跨域异常
@ExceptionHandler
public ResponseEntity<ErrorResponse> handleCorsException(CorsException ex) {
    ErrorResponse error = new ErrorResponse(
        "CORS_ERROR",
        ex.getMessage(),
        HttpStatus.FORBIDDEN.value()
    );
    return new ResponseEntity<>(error, HttpStatus.FORBIDDEN);
}
  1. 处理文件上传大小限制异常
@ExceptionHandler(MaxUploadSizeExceededException.class)
public ResponseEntity<ErrorResponse> handleMaxSizeException(
    MaxUploadSizeExceededException exc) {
    
    ErrorResponse error = new ErrorResponse(
        "FILE_TOO_LARGE",
        "File size exceeds the allowed limit",
        HttpStatus.BAD_REQUEST.value()
    );
    
    return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
}

六、总结

良好的异常处理是构建健壮Java应用程序的关键。通过合理使用Java原生异常机制和Spring的全局异常处理功能,可以:

  1. 提高代码的健壮性和可维护性
  2. 提供一致的用户体验
  3. 便于问题排查和调试
  4. 实现更好的系统监控

记住:异常处理的目标不是消灭所有异常,而是以可控的方式处理异常,并提供有意义的反馈。

你可能感兴趣的:(java,开发语言)