orElseGet 使用 ? extends T(生产者),要求 Supplier 返回 T 或其子类型;flatMap 使用 ? super T(消费者),允许 Function 接收 T 或其父类型,提升复用性。

Optional.orElseGet 和 Optional.flatMap 都涉及函数式接口参数,但它们对泛型类型的要求不同——这正是 PECS(Producer Extends, Consumer Super)原则发挥作用的地方。
PECS 原则提醒我们:
-
生产者(Producer)用
? extends T:方法返回T或其子类,调用方只读取结果,不往里塞值; -
消费者(Consumer)用
? super T:方法接收T或其父类,调用方往里传值,不依赖返回具体子类型。
orElseGet 是典型的“生产者”,用 ? extends T
orElseGet 的签名是:
public T orElseGet(Supplier<? extends T> other)
Supplier<? extends T> 表示:这个 Supplier 产出一个 T 或它的子类型。
为什么是 ? extends T?因为 orElseGet 最终要返回一个 T 类型的值,而 Supplier 只负责“提供”(produce),不接受输入。只要它能返回 T 或兼容类型(比如 String 是 CharSequence 的子类,那么 Supplier<String> 就可赋给 Supplier<? extends CharSequence>),就满足契约。
✅ 正确用法示例:
立即学习“Java免费学习笔记(深入)”;
Optional<String> opt = Optional.empty(); String s = opt.orElseGet(() -> "default"); // Supplier<String> → Supplier<? extends String>
⚠️ 错误理解(常见误区):
有人以为 orElseGet(Supplier<Object>) 也能接 Optional<String>,但这是编译不过的——Object 不是 String 的子类,Supplier<Object> 不能作为 Supplier<? extends String> 使用(反向不成立)。
flatMap 是典型的“消费者”,用 ? super T
flatMap 的签名是:
public <U> Optional<U> flatMap(Function<? super T, ? extends Optional<U>> mapper)
重点看前半部分:Function<? super T, ...>
它表示:这个 Function 接受 T 或其任意父类型(即它是 T 的消费者),比如 T 是 User,那 Function<Object, ...>、Function<Serializable, ...> 都合法。
为什么需要 ? super T?
因为 flatMap 要把当前 Optional<T> 里的值(类型为 T)传进去。如果限定死必须是 Function<T, ...>,那就无法复用更宽泛的函数(例如一个能处理所有 Object 的通用转换器)。放宽为 ? super T,提升了函数复用性。
同时后半部分 ? extends Optional<U> 是生产者视角:函数要返回 Optional<U> 或其子类型(虽然实践中几乎总是直接返回 Optional<U>)。
✅ 正确用法示例:
立即学习“Java免费学习笔记(深入)”;
Optional<User> userOpt = Optional.of(new User());
Optional<Address> addrOpt = userOpt.flatMap(u ->
Optional.ofNullable(u.getAddress())
);
// 这里 u 是 User 类型,但 Function 参数声明为 ? super User,
// 所以哪怕你写成 Function<Object, Optional<Address>> 也合法⚠️ 注意:flatMap 的 mapper 函数必须返回 Optional<U>,不能返回 U 或 null,否则会编译失败或运行时 NPE——这是和 map 的关键区别。
对比小结
| 方法 | 泛型参数位置 | PECS 角色 | 含义 | 实际约束 |
|---|---|---|---|---|
orElseGet |
Supplier<? extends T> |
生产者 | 提供一个 T 或子类型值 |
不能传 Supplier<Object> 给 Optional<String>
|
flatMap |
Function<? super T, ...> |
消费者 | 接收 T 或父类型,做转换 |
可传 Function<Object, ...> 给 Optional<String>
|
两者都靠 PECS 让接口更灵活、更安全:
-
orElseGet不强制你写Supplier<String>,允许Supplier<ConcreteStringSubclass>; -
flatMap不卡死你只能用Function<User, ...>,允许复用Function<Serializable, ...>处理多种实体。
不复杂但容易忽略。


















