核心是将“可能为空”从隐式假设变为显式契约:通过optional、不可变空集合、构造注入校验、安全访问方法、空对象模式、注解与工具链检查、明确api契约等方式,使null语义可表达、可约束、可追踪。

核心是把“可能为空”这个事实,从隐式假设变成显式契约。面向对象不是回避null,而是让null的语义可表达、可约束、可追踪。
属性声明阶段就切断隐患源头
不要依赖调用方记得判空,而要在类设计之初就控制属性的状态边界:
- 优先使用不可变且非空的类型:如String改用Optional
,集合类型统一用List 并初始化为Collections.emptyList(),而非null - 构造函数强制注入关键依赖:对业务逻辑强依赖的属性(如UserService、Config),用@NotNull标注参数,并在构造中调用Objects.requireNonNull()校验
- 避免公开可写字段:把属性设为private final,只通过带校验逻辑的setter或构建器暴露修改入口
访问逻辑封装进对象自身行为
把“取值+判空+兜底”打包成方法,而不是让外部反复写if (obj != null):
- 为可能为空的属性提供安全访问方法:例如getUserEmail()内部先判断email是否为null,再返回Optional.ofNullable(email)或默认值
- 用空对象模式替代null:定义EmptyUser extends User,重写getEmail()返回""或抛出业务异常,调用方无需分支处理
- 集合类属性统一返回不可变空集合:如getRoles()永远返回Collections.unmodifiableList(roles),即使roles是空列表,也绝不会返回null
用类型系统和工具链固化约束
让IDE和编译器帮你盯住空值风险点:
- 在字段、参数、返回值上添加@NonNull(JetBrains)或@Nonnull(JSR-305)注解,启用IDE的实时空值检查
- 在Maven/Gradle中集成SpotBugs或Error Prone,配置规则检测dereference of nullable value类问题
- 关键DTO或领域模型类启用Lombok的@RequiredArgsConstructor和@NonNull字段组合,编译期拦截未初始化字段
对外暴露接口时明确空值契约
让调用方清楚知道什么能空、什么不能空,而不是靠猜:
- API方法文档中明确定义:如findUserById(Long id)注明“返回Optional
,id不存在时返回Optional.empty()”,而非模糊写“可能返回null” - 区分“缺失”和“无效”语义:用Optional.empty()表示查无结果;用抛IllegalArgumentException表示传入非法id;不混用null承载两种含义
- JSON序列化时统一配置:如Jackson用@JsonInclude(JsonInclude.Include.NON_NULL)或NON_EMPTY,避免前端收到null字段后自行判空出错











