334. Java Stream API - 正确使用 Java Optional 的七大黄金法则 + 消费方法讲解

0 阅读3分钟

334. Java Stream API - 正确使用 Java Optional 的七大黄金法则 + 消费方法讲解


🔍 如何消费 Optional 的内容

Optional 提供了两个很实用的方法,可以“消费”它内部的值(如果有):

ifPresent(Consumer<T>)

这个方法的语义是:“如果有值,就处理它”。就像 Stream.forEach() 的缩小版。

📌 示例:

Optional<String> optional = Optional.of("Hello");
optional.ifPresent(value -> System.out.println("Value is: " + value));

输出:

Value is: Hello

如果 optional 是空的,啥也不发生。适合做 “可有可无的值的处理”


ifPresentOrElse(Consumer<T>, Runnable)

Java 9 加入的新方法。

📌 语义是:

  • 如果有值 → 执行第一个参数(Consumer
  • 如果没值 → 执行第二个参数(Runnable

📌 示例:

Optional<String> optional = Optional.empty();
optional.ifPresentOrElse(
    value -> System.out.println("Value is: " + value),
    () -> System.out.println("No value present!")
);

输出:

No value present!

🚀 用于在一个地方处理“有”和“无”的两种情况,更清晰更优雅。


🎯 七条 Optional 正确使用的黄金法则


✅ 规则 #1:绝对不要用 null 表示 Optional 没有值

错误做法 ❌:

Optional<String> optional = null; // 千万别这样!

正确做法 ✅:

Optional<String> optional = Optional.empty(); // 空的 optional

🔒 理由:Optional 的存在就是为了避免 null。如果你用 null 表示 Optional,反而制造了更大的风险!


✅ 规则 #2:除非你非常确定,别用 get()orElseThrow()

错误用法(风险巨大)❌:

String value = optional.get(); // 如果是 empty,就抛异常

更安全的做法 ✅:

optional.ifPresent(val -> System.out.println("Found: " + val));

或者配合 orElse()orElseGet()

String value = optional.orElse("default");

⚠️ 仅在你百分之百确信 Optional 一定有值的地方,才使用 get()orElseThrow()


✅ 规则 #3:尽量避免用 ifPresent() / get() / orElseThrow() 作流程控制

👎 不推荐的 ifPresent + else 模式:

if (optional.isPresent()) {
    doSomething(optional.get());
} else {
    doSomethingElse();
}

👍 更推荐:

optional.ifPresentOrElse(
    this::doSomething,
    this::doSomethingElse
);

更函数式、更现代化、更清晰。


✅ 规则 #4:不要用 Optional 来替代 null 判断

错误使用 ❌:

Optional<String> optional = Optional.ofNullable(name);
if (optional.isPresent()) {
    // do something
}

更直接做法 ✅:

if (name != null) {
    // do something
}

📌 Optional 是为了作为方法返回值的契约,不是为了你写 if 判断时图省事。


✅ 规则 #5:不要在以下位置使用 Optional:

❌ 错误用法原因
Optional 作为字段不序列化,且使用成本高
Optional 作为方法参数调用者很不方便传入
Optional 放在集合中组合复杂度高,性能低
Optional 做为 Map造成空值和逻辑判断的双重复杂度

正确做法 ✅:

  • 方法参数用 @Nullablejavadoc 说明
  • 字段用普通引用 + 文档约定

✅ 规则 #6:不要对 Optional 做身份比较或同步操作

错误示例 ❌:

if (optional1 == optional2) { ... } // 引用比较没有意义

更正确做法 ✅:

if (optional1.equals(optional2)) { ... }

同步也是危险的:

synchronized(optional) { ... } // 千万别这么写

原因:Optional 是值对象,不该参与同步、锁等“身份敏感操作”。


✅ 规则 #7:**Optional 不是可序列化的对象**

在 Java 的设计中,Optional 明确不是 Serializable。因此不能用于:

  • 网络传输对象
  • 存储结构
  • JSON 序列化

替代方法 ✅:

  • 使用 null + 文档说明
  • 自定义 Optional 类型并实现 Serializable(仅在必要场景下)

🧠 总结口诀(便于记忆)

🌱 可选非空不用 null, 🔐 拿值之前先判断, ✋ 少用 get,多用 map, 🧹 不用 Optional 做成员, 🚫 不要同步或比身份。