高并发下避免npe需契约明确、入口统一、线程安全、失败快速:用@nonnull+objects.requirenonnull做方法级守门;web入口通过filter/interceptor统一校验;查询结果用optional封装强制处理分支;工厂/builder在创建阶段杜绝非法null。

在高并发场景下,空指针异常(NPE)往往不是单点问题,而是因校验缺失、时序竞争或共享状态不一致导致的连锁故障。前置非空校验不是简单加个 if (x == null),而是通过**契约明确、入口统一、线程安全、失败快速**的设计,把空值挡在业务主干之外。
用 @NonNull + Objects.requireNonNull 做方法级契约守门
在接口或服务方法入口,对关键参数做显式非空断言:
- 标注
@NonNull(如 Spring 的org.springframework.lang.NonNull或 Jakarta 的jakarta.validation.constraints.NotNull),让 IDE 和静态检查工具提前预警 - 配合
Objects.requireNonNull(param, "userId must not be null"),确保一旦传入 null,立刻在调用处抛出带上下文的异常,堆栈清晰、定位精准 - 避免在循环体或高频路径中滥用——它不是流程控制,而是“契约违约”的即时响应
在 Web 入口统一拦截:Filter/Interceptor 中做并发安全校验
所有外部请求(HTTP、RPC)都必须经过这一层,天然适合集中防御:
- 使用 Spring 的
HandlerInterceptor或标准 ServletFilter,确保它是 Spring 管理的 Bean(不能 new) - 提取关键字段(如
userId、token、orderId),用Objects.requireNonNull()或自定义校验器判断是否为空 - 校验失败时直接返回 HTTP 400,并写入结构化错误信息(如
{"code":"INVALID_PARAM","message":"missing userId"}),不放行到 Controller - 注意:校验逻辑本身要无状态、无副作用,避免锁或全局变量,保障高并发下的吞吐与一致性
用 Optional 封装可能为空的查询结果,强制调用方处理分支
数据库查询、远程 Feign 调用、缓存 get 等操作,天然存在“查不到”的语义,返回 null 是设计缺陷:
- 将方法签名改为
Optional<user> findUserById(Long id)</user>,而非User findUserById(Long id) - 调用方必须显式决策:用
orElseThrow(UserNotFoundException::new)表达“必须存在”,或用ifPresent(...)/map(...).orElse(...)处理有无两种路径 - Optional 仅用于返回值,不作为字段、参数或集合元素——否则会掩盖真实语义,增加理解成本
工厂/Builder 封装对象创建,从源头杜绝非法 null 状态
对象一旦构造完成,就应满足业务前提。把校验前移到创建阶段,比处处判空更彻底:
- 定义
UserFactory接口,createValidUser(String name, String email)方法内部校验 name 非空、email 格式合法,不满足则抛IllegalArgumentException - 使用 Builder 模式时,在
build()中做终态检查:if (this.name == null) throw new IllegalStateException("name is required") - 配合 Lombok 的
@RequiredArgsConstructor(onConstructor_ = @NonNull),让编译期就拒绝 null 构造参数











