Optional.ifPresentOrElse() 提供互斥的值存在/不存在处理机制,接收Consumer和Runnable参数,避免重复判空与解包,适用于配置读取等场景,但不可返回值且需注意线程安全。

Java 9 引入的 Optional.ifPresentOrElse() 提供了一种简洁、无副作用的方式来统一处理“值存在”和“值不存在”两种情况,避免了传统 if (opt.isPresent()) 的冗余判断和潜在的重复解包。
理解 ifPresentOrElse 的签名与语义
该方法定义为:
public void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction)
它接收两个参数:
- action:当 Optional 包含非 null 值时执行,入参是该值本身(自动解包)
- emptyAction:当 Optional 为 empty(null 或空容器)时执行,无参数
关键点在于:两者是互斥执行的,且都是一次性消费行为,不返回值、不改变 Optional 状态,天然符合函数式编程中“副作用可控”的理念。
立即学习“Java免费学习笔记(深入)”;
替代传统 if-else 的典型场景
常见于配置读取、缓存查询、API 响应解析等需要明确区分“有数据”和“无数据”路径的场景:
- 以前这样写:
if (userOpt.isPresent()) { sendWelcomeEmail(userOpt.get()); } else { logMissingUser(); } - 现在可改写为:
userOpt.ifPresentOrElse(this::sendWelcomeEmail, this::logMissingUser);
没有 get() 调用,没有重复判空,逻辑扁平,意图清晰。注意:两个方法引用必须是无参(emptyAction)或单参(action)且不能抛受检异常。
结合链式调用与副作用控制
它常与 map、filter 等组合使用,在流式处理中保持逻辑连贯:
configOpt
.map(Config::getRetryPolicy)
.filter(policy -> policy.getMaxRetries() > 0)
.ifPresentOrElse(
policy -> startWithRetry(policy),
() -> startWithoutRetry()
);
整个链条从配置提取、转换、过滤到最终分支执行一气呵成,中间任意环节为 empty 都会自然落入 emptyAction 分支,无需额外中断或嵌套。
注意事项与避坑点
使用时需留意以下细节:
- 不能用于需要返回值的场景——它返回
void,如需构造结果,请用orElse或orElseGet - 两个 lambda 或方法引用不应修改共享状态,否则可能引发竞态;若必须记录日志或发通知,确保操作是线程安全或幂等的
- 不要在
action中再次调用get()或isPresent()——这违背设计初衷,也失去自动解包的意义 - 若
emptyAction需要访问上下文信息(比如原始 key),建议提前捕获变量:String key = "timeout"; cache.get(key).ifPresentOrElse(v -> use(v), () -> handleMiss(key));


















