Java Optional.orElse执行逻辑疑问:全局变量为何未按预期更新?
问题解析:Optional.orElse调用后字符串拼接不符合预期的原因
问题重现
测试代码:
import java.util.Optional; public class OptionalTest { static String globalString = "Hello"; public static void main(String... optional) { String otherString = "Other"; globalString += Optional.of(otherString) .orElse(updateString()); System.out.println(globalString); } static String updateString() { System.out.println("It's called"); globalString = "Not Hello"; return "Another"; } }
实际输出:
It's called HelloOther
预期输出:
It's called Not HelloOther
核心原因
这两个关键点导致结果不符合预期:
1. 字符串拼接表达式的求值顺序
Java中,globalString += X 本质等价于 globalString = globalString + X。该表达式的求值顺序为先读取等号右侧的globalString当前值并暂存,再计算X,最后将拼接结果赋值给globalString。
在你的代码里,执行globalString += ...时,第一步会先读取globalString的初始值"Hello"并暂存,之后才会执行右侧的Optional.of(otherString).orElse(updateString())逻辑。
2. Optional.orElse的参数是立即求值的
orElse的参数是普通对象,而非延迟执行的Supplier,因此无论Optional是否包含非空值,都会先执行参数表达式。所以这里updateString()会被调用:
- 打印
It's called - 将
globalString修改为"Not Hello" - 返回
"Another"
但由于Optional.of(otherString)包含有效值"Other",orElse最终返回的是otherString的值"Other",而非updateString()的返回值。
最终执行流程
拆解整个执行步骤:
- 读取
globalString初始值"Hello"并暂存,用于后续拼接。 - 执行
Optional.of(otherString),得到包含"Other"的Optional实例。 - 执行
orElse的参数updateString():打印日志,修改globalString为"Not Hello",返回"Another"。 - 因Optional存在有效值,
orElse返回"Other"。 - 用暂存的
"Hello"和"Other"拼接,得到"HelloOther"。 - 将
"HelloOther"赋值给globalString,覆盖之前的"Not Hello"。 - 打印最终的
globalString值"HelloOther"。
解决方法
如果想要实现懒加载(仅当Optional为空时执行updateString()),且让拼接使用修改后的globalString,可做如下调整:
- 用
orElseGet替代orElse,orElseGet接收Supplier接口实现,仅当Optional为空时才执行对应逻辑。 - 调整代码顺序,先执行Optional相关逻辑修改
globalString,再进行拼接。
修改后的示例代码:
import java.util.Optional; public class OptionalTest { static String globalString = "Hello"; public static void main(String... optional) { String otherString = "Other"; // 先处理Optional逻辑 String result = Optional.ofNullable(null) // 模拟空Optional场景 .orElseGet(() -> updateString()); // 再执行拼接 globalString += result; System.out.println(globalString); } static String updateString() { System.out.println("It's called"); globalString = "Not Hello"; return "Another"; } }
此时输出会符合预期:
It's called Not HelloAnother
内容的提问来源于stack exchange,提问作者Ale
相关产品推荐
相关产品推荐

