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></string> 就可赋给 Supplier extends CharSequence>),就满足契约。
✅ 正确用法示例:
Optional<string> opt = Optional.empty(); String s = opt.orElseGet(() -> "default"); // Supplier<string> → Supplier extends String></string></string>
⚠️ 错误理解(常见误区):
有人以为 orElseGet(Supplier<object>)</object> 也能接 Optional<string></string>,但这是编译不过的——Object 不是 String 的子类,Supplier<object></object> 不能作为 Supplier extends String> 使用(反向不成立)。
flatMap 是典型的“消费者”,用 ? super T
flatMap 的签名是:
public <u> Optional<u> flatMap(Function super T, ? extends Optional<u>> mapper)</u></u></u>
重点看前半部分:Function super T, ...>
它表示:这个 Function 接受 T 或其任意父类型(即它是 T 的消费者),比如 T 是 User,那 Function<object ...></object>、Function<serializable ...></serializable> 都合法。
为什么需要 ? super T?
因为 flatMap 要把当前 Optional<t></t> 里的值(类型为 T)传进去。如果限定死必须是 Function<t ...></t>,那就无法复用更宽泛的函数(例如一个能处理所有 Object 的通用转换器)。放宽为 ? super T,提升了函数复用性。
同时后半部分 ? extends Optional<u></u> 是生产者视角:函数要返回 Optional<u></u> 或其子类型(虽然实践中几乎总是直接返回 Optional<u></u>)。
✅ 正确用法示例:
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>> 也合法</object>
</address></user>
⚠️ 注意:flatMap 的 mapper 函数必须返回 Optional<u></u>,不能返回 U 或 null,否则会编译失败或运行时 NPE——这是和 map 的关键区别。
对比小结
| 方法 | 泛型参数位置 | PECS 角色 | 含义 | 实际约束 |
|---|---|---|---|---|
orElseGet |
Supplier extends T> |
生产者 | 提供一个 T 或子类型值 |
不能传 Supplier<object></object> 给 Optional<string></string>
|
flatMap |
Function super T, ...> |
消费者 | 接收 T 或父类型,做转换 |
可传 Function<object ...></object> 给 Optional<string></string>
|
两者都靠 PECS 让接口更灵活、更安全:
-
orElseGet不强制你写Supplier<string></string>,允许Supplier<concretestringsubclass></concretestringsubclass>; -
flatMap不卡死你只能用Function<user ...></user>,允许复用Function<serializable ...></serializable>处理多种实体。
不复杂但容易忽略。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











