推荐用 Optional.orElseThrow() 结合自定义异常(如 ResourceNotFoundException)处理资源缺失,精准映射 HTTP 状态码;避免手动判空,仅对 Repository 查询等存在性不确定场景使用,不用于参数校验。

在 RESTful API 开发中,当请求参数、路径变量或数据库查询结果缺失时,直接抛出通用异常(如 NullPointerException)会破坏语义清晰性,也不利于前端统一处理。用 Optional.orElseThrow() 结合自定义业务异常,能精准表达“资源未找到”“参数非法”等语义,让错误响应状态码、消息体都符合 HTTP 规范。
用orElseThrow替代if-else判空,明确失败语义
传统写法常先 if (obj == null) 再 throw,逻辑分散且易遗漏;而 Optional 将“存在性”显式建模,orElseThrow 一步完成“检查 + 抛错”,代码更紧凑,意图更清晰。
- ✅ 推荐:将 DAO 查询结果包装为
Optional<User>,调用userRepo.findById(id).orElseThrow(() -> new ResourceNotFoundException("User not found: " + id)) - ❌ 避免:手动判空后 new 异常,既冗余又容易忘记设置 HTTP 状态码
搭配自定义异常类,绑定HTTP状态码
orElseThrow() 接收 Supplier,适合构造带状态码的异常。定义如 ResourceNotFoundException 继承 RuntimeException,并在全局异常处理器(@ControllerAdvice)中映射为 404 NOT_FOUND。
- 定义异常:// 不需额外字段,仅作语义标识
public class ResourceNotFoundException extends RuntimeException { public ResourceNotFoundException(String msg) { super(msg); } } - 全局处理:
@ResponseStatus(HttpStatus.NOT_FOUND)注解该异常类,或在@ExceptionHandler中显式设置响应体与状态码
路径/查询参数校验场景下的自然衔接
Spring MVC 的 @PathVariable 或 @RequestParam 本身不返回 Optional,但可结合 Service 层返回值使用。例如:
前端请求 GET /api/users/123 → Controller 调用 userService.findById(123L) → Service 返回 Optional<User> → Controller 用 orElseThrow 转换异常。
- 关键点:不要在 Controller 层对原始参数做
Optional.ofNullable(param).orElseThrow(...)—— 这属于非法输入,应走 Bean Validation(如@NotNull)或@Valid - 适用边界:仅用于“资源存在性”判断(如查库、查缓存),而非基础参数合法性校验
避免过度包装,保持异常粒度合理
不是所有 null 都值得转成 Optional。若方法本就明确可能返回 null(如 MyBatis 的 selectOne),包装是合理的;但若已有非空契约(如 JDK 方法文档声明 non-null),强行 Optional 反而增加认知负担。
- 推荐包装:Repository 查询方法、外部 SDK 返回可能为 null 的对象
- 谨慎包装:DTO 构造器参数、内部工具方法返回值——此时更应修复设计,或用断言
- 注意性能:
Optional是轻量对象,但高频调用中避免无意义创建(如循环内反复包装)

















