Wrayの知识库 Wrayの知识库
首页
  • Java 基础
  • Java 集合
  • Java 并发
  • Java IO
  • JVM
  • Spring Framework
  • Spring Boot
  • Spring Cloud
  • Spring Security
  • MySQL
  • Redis
  • 计算机基础
  • 操作系统原理
  • Linux
  • MacOS
  • Windows
  • 系统工程与研究专题
  • AI 基础
  • 大模型基础
  • Prompt 工程
  • RAG 检索增强生成
  • Agent 智能体
  • AI 应用开发
  • AI 工程化
  • AI 安全与治理
  • AI 面试与设计题
  • 纸质书
  • 电子书
  • 学习课程
疑难杂症
GitHub (opens new window)
首页
  • Java 基础
  • Java 集合
  • Java 并发
  • Java IO
  • JVM
  • Spring Framework
  • Spring Boot
  • Spring Cloud
  • Spring Security
  • MySQL
  • Redis
  • 计算机基础
  • 操作系统原理
  • Linux
  • MacOS
  • Windows
  • 系统工程与研究专题
  • AI 基础
  • 大模型基础
  • Prompt 工程
  • RAG 检索增强生成
  • Agent 智能体
  • AI 应用开发
  • AI 工程化
  • AI 安全与治理
  • AI 面试与设计题
  • 纸质书
  • 电子书
  • 学习课程
疑难杂症
GitHub (opens new window)
  • Java章节编写规范
  • Java基础

    • Java概述
    • Java语法
    • 面向对象编程
    • Java数组
    • String字符串
    • 异常处理
    • 基本类型与包装类
    • Object类与常用方法
    • 泛型
    • 枚举与注解
    • 反射
    • 值传递与引用
    • Lambda表达式与函数式接口
    • Stream API
    • Optional与空值处理
      • 1. 为什么需要 Optional
      • 2. 创建 Optional
      • 3. 获取值
      • 4. orElse 与 orElseGet
      • 5. map 与 flatMap
      • 6. filter
      • 7. Optional 使用边界
      • 8. Optional 与集合
      • 9. 常见误区
      • 10. 空值设计方法论
      • Tips 快问快答
    • 日期时间API
    • Java现代语法特性
  • Java集合

  • Java并发

  • Java IO

  • JVM

目录

Optional与空值处理

Optional 是 Java 8 引入的容器类,用于显式表达“一个值可能存在,也可能不存在”。它的目标不是消灭 null,而是让返回值的空语义更清晰。

# 1. 为什么需要 Optional

传统写法:

User user = repository.findById(id);
if (user != null) {
    return user.getName();
}
return "unknown";

Optional 写法:

String name = repository.findById(id)
        .map(User::getName)
        .orElse("unknown");

方法签名:

Optional<User> findById(Long id);

调用方一眼能看出结果可能不存在。

# 2. 创建 Optional

Optional<User> empty = Optional.empty();
Optional<User> user = Optional.of(new User());
Optional<User> nullable = Optional.ofNullable(maybeNull);

区别:

方法 null 行为
empty 创建空 Optional
of 参数为 null 时抛 NPE
ofNullable 参数为 null 时返回 empty

如果值可能为 null,使用 ofNullable。

# 3. 获取值

不推荐:

User user = optional.get();

如果为空会抛 NoSuchElementException。

推荐:

User user = optional.orElse(defaultUser);

或:

User user = optional.orElseThrow(() -> new BusinessException("USER_NOT_FOUND"));

# 4. orElse 与 orElseGet

User user = optional.orElse(createDefaultUser());

orElse 的参数会提前计算。

User user = optional.orElseGet(() -> createDefaultUser());

orElseGet 只有为空时才执行 Supplier。

流程:

Optional 有值
  ├─ orElse:默认值已提前创建
  └─ orElseGet:不执行 Supplier

默认值创建成本高时,优先 orElseGet。

# 5. map 与 flatMap

Optional<String> name = optionalUser.map(User::getName);

如果映射函数本身返回 Optional:

Optional<Address> address = optionalUser.flatMap(User::getAddressOptional);

flatMap 避免嵌套:

Optional&lt;Optional&lt;Address>>
  │ flatMap
  ▼
Optional&lt;Address>

# 6. filter

Optional<User> activeUser = optionalUser
        .filter(User::isActive);

如果有值且满足条件,保留;否则变 empty。

# 7. Optional 使用边界

推荐用于:

  • 方法返回值。
  • 查询可能无结果。
  • 链式处理可空结果。

不推荐用于:

  • 实体字段。
  • DTO 字段。
  • 方法参数。
  • 集合元素大量包装。

不推荐:

public void save(Optional<User> user) {
}

参数可空时,直接校验或重载方法通常更清楚。

# 8. Optional 与集合

不要返回 Optional<List<T>> 表达无结果。

推荐:

List<User> queryUsers();

无结果返回空集合:

return Collections.emptyList();

集合本身已经能表达“没有元素”。

# 9. 常见误区

  • 把 Optional.get() 当普通 getter。
  • 用 Optional 字段影响序列化和 ORM。
  • 过度链式调用导致可读性下降。
  • 用 Optional 包装集合。
  • 方法参数使用 Optional 增加调用成本。

# 10. 空值设计方法论

Optional 不是语法装饰,而是一种 API 契约。它告诉调用方:“这里没有结果是正常业务分支,不是异常。”

查询用户
  ├─ 找到:Optional.of(user)
  └─ 未找到:Optional.empty()

调用方
  ├─ map 转换
  ├─ filter 过滤
  ├─ orElseGet 兜底
  └─ orElseThrow 转业务异常

不同空语义要用不同表达:

语义 推荐表达 示例
单个结果可能不存在 Optional<T> findById
多个结果为空 空集合 queryOrders
参数非法 抛异常 requireNonNull
字段可选 普通字段 + 文档/校验 DTO、实体
远程调用失败 异常或 Result 和“无结果”区分

不要把所有 null 都机械替换为 Optional。例如数据库实体、JSON DTO、RPC 入参里使用 Optional,往往会增加序列化、框架绑定和调用方理解成本。

专家级空值处理通常遵循:

  • 输入参数尽早校验。
  • 内部逻辑尽量减少可空变量传播。
  • 返回值用类型表达正常的“无结果”。
  • 异常表达非预期失败。
  • 集合无结果返回空集合。

# Tips 快问快答

Q:Optional 是为了完全替代 null 吗? A:不是,它主要用于返回值显式表达可能为空。

Q:Optional.get 推荐用吗? A:不推荐,除非已经明确判断有值。

Q:orElse 和 orElseGet 区别是什么? A:orElse 参数提前计算,orElseGet 为空时才计算。

Q:Optional 适合做字段吗? A:通常不适合,尤其是实体、DTO、序列化对象。

Q:方法参数应该用 Optional 吗? A:通常不推荐,直接校验或重载更清晰。

Q:查询列表无结果返回什么? A:返回空集合,不要返回 null 或 Optional<List<T>>。

Q:map 和 flatMap 区别? A:map 转换普通值,flatMap 展开 Optional 结果。

Q:Optional 能避免所有 NPE 吗? A:不能,错误使用仍然会产生异常或空语义混乱。

上次更新: 2026/06/25, 14:19:18
Stream API
日期时间API

← Stream API 日期时间API→

Copyright © 2023-2026 Wray | 鄂ICP备2024050235号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式