Java null 与 Optional

Java 引用可空主模型与 Optional 的正确用法:何时用 null、何时用 Optional、如何降低 NPE。

#type / concept #status / growing #tech / dev #resource / java

[!info] 关联笔记

Java null 与 Optional

这个概念为什么出现

引用类型变量可以是 null,表示“没有对象”。这是 Java 历史主模型,也是 NullPointerException 之源。Optional 在标准库层表达“可能缺失的返回值”,但不能消灭语言级 null。

[!abstract] 一句话理解 null 是引用的缺省空值;Optional<T> 用于明确“可能无结果”的返回场景,应用 map/flatMap/orElse 显式处理,而不是替代所有字段。

最小可运行示例

场景:用户中心按 ID 查找,找不到时不能假装有用户

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

public class UserLookup {
    private final Map<String, String> db = new HashMap<>();

    UserLookup() {
        db.put("u1", "Ada");
    }

    // 返回 Optional:调用方必须处理缺失
    Optional<String> findName(String id) {
        return Optional.ofNullable(db.get(id));
    }

    static String display(Optional<String> name) {
        return name.map(n -> "hi " + n).orElse("hi guest");
    }

    public static void main(String[] args) {
        UserLookup ul = new UserLookup();
        System.out.println(display(ul.findName("u1")));
        System.out.println(display(ul.findName("missing")));
        // 错误示范:Optional 解包前不检查
        // ul.findName("missing").get(); // NoSuchElementException
    }
}

建议运行:

javac UserLookup.java && java UserLookup

期望输出:

hi Ada
hi guest

结合场景再看三个关注点

  1. 找不到用空 Optional,而不是 null 返回又文档不写
  2. get() 是尖刀,优先 orElse/orElseThrow
  3. 字段仍可用 null 或明确缺省对象,不要把 Optional 塞满领域模型。

核心概念与准确模型

1. null 出现位置

  • 未初始化对象引用字段默认 null
  • 容器缺失、Map.get 未命中
  • 外部 API 失败用 null(坏风格)

2. NPE 典型路径

  • 对 null 调方法/访字段
  • 拆箱 Integerint 时为 null
  • 自动拆箱与链式调用

3. Optional 适用

适合不适合
返回值可能缺失方法参数(通常)
明确替代 null 返回实体字段到处 Optional
链式变换当集合用(别 Optional 嵌套爆炸)

4. 防御技术

  • Objects.requireNonNull
  • 早期校验
  • 空对象模式(有限度)
  • 注解/静态分析(工程篇)

边界情况与反直觉行为

  1. Optional.of(null) 立即 NPE;用 ofNullable
  2. orElse(getDefault())无条件执行默认工厂——应用 orElseGet
  3. 序列化与 Optional 字段兼容性视技术栈而定。

常见误区

[!warning] 常见误区:return null 表示错误 错误应用异常或 Result 类型语义;null 表示“无值”,不是“失败原因”。

工程实践

  1. 公共 API 返回缺失用 Optional 或明确空集合(不要返回 null 集合)。
  2. 集合返回 List.of()/Collections.emptyList() 优于 null。
  3. 日志与指标记录 NPE 发生点,修根因而非全局 catch。
  4. 与 Kotlin 互操作时注意平台类型。

本节总结

  • null 是主模型;Optional 是返回值工具
  • 显式处理缺失;避免伪装成功
  • 空集合优于 null 集合

自测题

  1. 何时用 orElseGet 而不是 orElse
  2. 为什么不建议 Optional 作所有字段类型?
参考答案
  1. 默认值创建有开销或副作用时延迟执行。
  2. 增加分配与嵌套复杂度,领域模型更宜不可变与明确缺省。

延伸阅读与资料来源

资料类型支撑内容
Optional (Java SE)APIOptional 语义
JLS 关于引用类型与 null规范null 类型
创建于 2026/7/15 更新于 2026/7/15