Spring Boot 中异常捕获与处理指南
目录
1. 背景
在 Spring Boot 开发中,异常处理是确保应用程序健壮性和用户体验的关键部分。本文档通过示例代码,讲解异常捕获和抛出的原则。
2. Java 异常分类
| 异常类型 | 描述 | 是否必须捕获 | 例子 |
|---|---|---|---|
| Checked Exception | 继承自 Exception(但不是 RuntimeException),编译时强制处理 | 是(try-catch 或 throws) | IOException, SQLException |
| Unchecked Exception | 继承自 RuntimeException,运行时异常,不强制处理 | 否 | IllegalArgumentException, NullPointerException |
3. 示例场景
3.1 服务层代码
1 | @Service |
3.2 控制器代码
1 | @RestController |
4. 是否需要显式捕获异常?
4.1 不需要显式捕获的情况
默认处理:Spring Boot 返回 500:
1
{"status": 500, "error": "Internal Server Error", "message": "订单 ID 不能为空"}
全局处理:已有 @ControllerAdvice。
4.2 需要显式捕获的情况
自定义响应:
1
2
3
4
5
6
7
8@GetMapping("/orders/{id}")
public ResponseEntity<String> getOrder(@PathVariable String id) {
try {
return ResponseEntity.ok(orderService.getOrderDetails(id));
} catch (IllegalArgumentException e) {
return ResponseEntity.badRequest().body("错误: " + e.getMessage());
}
}
5. 是否需要显式往外抛出异常?
5.1 什么时候需要抛出?
未检查异常(如 IllegalArgumentException) :
需要抛出:表示方法无法继续执行,通知调用者问题。
无需声明 throws:运行时异常自动传播。
示例:
1
2
3
4
5
6public String getOrderDetails(String orderId) {
if (orderId == null) {
throw new IllegalArgumentException("订单 ID 不能为空");
}
return "Order: " + orderId;
}
受检异常(如 IOException) :
需要抛出并声明 throws:如果方法无法处理。
示例:
1
2
3public String readFile() throws IOException {
return Files.readString(Paths.get("file.txt"));
}
5.2 什么时候不需要抛出?
内部消化:
1
2
3
4
5
6public String getOrderDetails(String orderId) {
if (orderId == null) {
return "默认订单";
}
return "Order: " + orderId;
}捕获后处理:
1
2
3
4
5
6
7
8public String getOrderDetails(String orderId) {
try {
return fetchOrder(orderId);
} catch (Exception e) {
log.error("获取失败", e);
return null;
}
}
5.3 Spring Boot 中的建议
- 运行时异常:抛出但无需声明 throws,交给全局处理器。
- 受检异常:抛出并声明 throws,或在适当层级捕获。
6. 哪些异常需要捕获?
| 异常类型 | 是否需要捕获? | 原因及建议 |
|---|---|---|
| Checked Exception | 是 | 编译器强制要求。 |
| IllegalArgumentException | 否(视情况) | 可抛出,交给全局处理;若需特定响应,则捕获。 |
| Custom Business Exception | 否(推荐全局处理) | 抛出自定义异常,统一处理。 |
7. 最佳实践:全局异常处理
1 | @RestControllerAdvice |
8. 总结
捕获:受检异常必须捕获,运行时异常可选。
抛出:
- 需要:无法处理时抛出,运行时异常无需 throws,受检异常需声明。
- 不需要:内部可消化或无需通知调用者时。
推荐:结合全局处理,抛出语义化异常。
Comments




