面向接口设计通过契约约束和依赖抽象在前置流程中防范空值风险。使用@nonnull/@nullable声明非空契约,配合工厂/builder封装对象创建并校验,用optional明确表达可能无值场景,结合拦截器统一入口校验,将空指针拦截在业务主干之外。

面向接口设计本身不直接拦截异常,但它能通过契约约束和依赖抽象,在前置流程中把空值风险“挡在门外”。关键不是等空指针发生后再捕获,而是让空值根本无法合法进入业务主干。
用接口定义非空契约
接口方法签名应明确表达参数/返回值的可空性,而非依赖运行时猜测。Spring Framework 5+ 的 @NonNull 和 @Nullable 是最轻量的契约声明方式:
- 在服务接口上标注
@NonNull User getUserById(@NonNull Long id),告诉调用方:传 null 就是违反契约,不该发生 - 配合 Lombok 的
@NonNull字段注解或构造器参数校验,让对象一创建就拒绝 null 值 - IDE 和编译器(如启用 Error Prone)会据此发出警告,问题暴露在编码阶段,而非上线后
用工厂或构建器封装对象创建逻辑
避免裸 new 或随意返回 null,把对象初始化过程收口到接口背后:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 定义
UserFactory接口,提供createValidUser(String name)方法,内部强制校验 name 非空并抛出IllegalArgumentException - 使用 Builder 模式时,在
build()方法里做最终校验:if (this.name == null) throw new IllegalStateException("name must not be null") - 这样下游拿到的对象天然满足业务前提,无需处处判空
用 Optional 作接口返回类型
当某个操作确实可能无结果(如查询不存在的用户),不要返回 User,而返回 Optional<user></user>:
- 调用方必须显式处理“无值”情况:
userOpt.orElseThrow(() -> new UserNotFoundException())或userOpt.ifPresent(this::process) - 它把“是否为空”从隐式状态变为显式 API 行为,迫使调用逻辑在前置流程中就决策,而不是等到
user.getName()才崩 - 注意:Optional 不适合用作字段或参数,仅推荐用于返回值
在拦截器或 Filter 中做统一入口校验
对 Web 层请求,利用 Spring 的 HandlerInterceptor 或 Servlet Filter 做前置守门人:
- 提取关键参数(如 userId、token),用
Objects.requireNonNull()或自定义校验器判断是否为空 - 若校验失败,直接设置响应状态码 400 并返回错误信息,不放行到 Controller
- 务必确保拦截器是 Spring 容器管理的 Bean(用
@Autowired注入,而非new Interceptor()),否则依赖注入失效会导致二次 NPE










