Java异常体系
编程讲究强壮性
即确保代码在错误发生时
能按预案妥善处理
Throwable是所有异常的父级
分为两大类:Error和Exception
Error表示系统级错误
通常由JVM抛出
无法由程序处理
而Exception表示程序可处理的异常
需要程序员编码进行处理

RuntimeException
Java里异常分为受检异常和非受检异常
受检异常包括 IOException、ClassNotFoundException
这类异常可以预判到
基本上源自外部因素和环境问题
比如文件有可能读不到
类包没有引入等等
简单判断是不是受检异常
你看到IDE提示需要 try-catch 或 throws 那就是了
复杂的是RuntimeException
顾名思义
只有在运行时才能遭遇
表示程序本身有bug
例如最常见的 NullPointException
对象引用为空 或是没有初始化
到底用哪种异常是初学者最头疼的问题
简而言之
Exception 可以进行 重试、降级、中断等操作
而 Runtime 则应修复代码逻辑
举个例子
操作系统环境、网络等问题配置错误导致的
就用Exception
而Runtime都是与正在运行的代码逻辑相关的
典型Runtime
我们编写代码时会内置很多逻辑规则
当业务规则被违反时
应使用RuntimeException
典型Runtime场景如下:
当用户输入不符合预期时,例如长度、类型不正确
当出现数据库操作逻辑错误时,例如SQL写错无法执行
当出现业务逻辑错误时
当系统内部状态不一致时
当出现无法通过外部干预解决的问题时
当需要立即终止当前操作并修复代码时
当出现系统内部bug时
当出现设计缺陷时
当需要立即修复代码而不是处理异常时
Java内置了很多Runtime的子类
根据典型场景可以选择使用
例如
当对象未初始化时,应使用子类 NullPointerException
当出现算术错误时,例如除0,应使用子类 ArithmeticException
当出现数组索引越界时,应使用子类 IndexOutOfBoundsException
当出现类型转换错误时,应使用子类 ClassCastException
当出现并发修改异常时,应使用子类 ConcurrentModificationException
当出现数据存储不一致时,应使用子类 ArrayStoreException
当出现空指针时,应使用子类 NullPointerException
当出现参数错误时,应使用子类 IllegalArgumentException
典型Exception
对比Exception
大都是源自于外界因素
通过修改外部环境或者配置都能解决
正常情况下不应出现Exception
典型场景有:
当需要返回错误码给前端时
当需要处理网络超时时
当需要处理数据库事务回滚时
以及常用的子类包括:
当数据库连接失败时,应使用子类 SQLException
当文件系统操作失败时,应使用子类 IOException
当网络通信失败时,应使用子类 OException
当配置文件不存在时,应使用子类 FileNotFoundException
使用场景归纳
请不要在代码里人工补货 Runtime
例如 Controller、Service、Dao
出现 Runtime 就让他返回更高层
这样可以将异常信息反馈到 View
告诉用户,他违反了什么规则
例如:余额不足、输入为负数、手机号不是11位、没有权限等
特别在Spring项目中
采用 Runtime 就无须层层 throw
可以通过 @ControllerAdvice
在 Controller 返回给前端时
记录日志,并返回友好的错误信息给前端
同时转换为 401、500 等标准 HTTP 状态码
例如:
/**
* 自定义异常类
*/
public class BusinessException extends RuntimeException {
private final String code;
private final String traceId;
public BusinessException(String code, String message) {
super(message);
this.code = code;
this.traceId = java.util.UUID.randomUUID().toString().replace("-", "");
}
}
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
/**
* 处理自定义业务异常
* HTTP 400 (Bad Request)
*/
@ExceptionHandler(value = BusinessException.class)
public ResponseEntity<ApiResponse<Void>> handleBusinessException(BusinessException e) {
log.warn("业务异常: code={}, message={}, traceId={}", e.getCode(), e.getMessage(), e.getTraceId());
ApiResponse<Void> response = ApiResponse.fail(e.getCode(), e.getMessage());
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response);
}
/**
* 处理所有未预期的系统异常 (如: NullPointerException, RuntimeException)
* 对前端返回通用的"系统繁忙"信息,避免暴露敏感信息
* 记录详细错误日志用于排查
* 返回 HTTP 500
*/
@ExceptionHandler(Exception.class)
public ResponseEntity<ApiResponse<Void>> handleUnexpectedException(Exception e) {
String traceId = java.util.UUID.randomUUID().toString().replace("-", "");
log.error("系统内部异常 [TraceID={}]: {}", traceId, e.getMessage(), e);
ApiResponse<Void> response = ApiResponse.fail("SYSTEM_ERROR", "系统繁忙,请稍后重试");
response.setTraceId(traceId);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
}
}
这样就能够清晰地传递错误信息
便于调试和处理
确保系统的健壮、可维护