为什么 Java 不优化 |= 赋值?



对于此示例,t*()始终返回 true,而 asf*()始终返回 false。

假设我们有以下表达式

if ( f1() || t1() || f2() || t2() ){
// do stuff        
}

如果是这种情况,JVM 会优化执行并且只执行f1()t1(),因为它"理解"无论f2()t2()产生什么结果,都满足输入 if 语句的要求,因此不需要进一步计算。

我正在编写一段代码,其中我写了这样的东西:

boolean b = false;
b |= f1(); // A
b |= t1(); // B
b |= f2(); // C
b |= t2(); // D

我的一位同事看到了这一点,并提到他不确定,但是Java可能会优化语句C和D,因为b总是从语句B开始true,这可能会导致一些问题。

我进行了一些测试,似乎所有这些都正确执行(这是所需的行为(,但我仍然想知道为什么没有优化?我认为他可能是对的,JVM明白,一旦b为真,|=对其进行操作都不会改变其值。

调用不会因为 JLS §15.26.2 而优化。复合赋值运算符需要计算右侧表达式。

如果左侧操作数表达式不是数组访问表达式,则:

  • 首先,评估左操作数以产生 一个变量。如果此评估突然完成,则作业 出于同样的原因,表达式突然完成;右手 不计算操作数,也不会发生分配。
  • 否则,将保存左侧操作数的值,然后计算右侧操作数。

从历史上看,短路条件(&&||(而不是按位(&|(运算符的传统至少可以追溯到C(但值得注意的是,C直到1999年才有明确的布尔类型(。

我仍然想知道为什么这没有得到优化?

因为这将违反JLS。

声明

b |= f1();

相当于

b = (boolean)(b | f1());

在上述中,JLS要求按如下方式评估b | f1()

  1. 获取b的值。
  2. 调用f1()并捕获结果值
  3. |运算符应用于这两个值。

如果btrue1,则 JLS不允许编译器跳过调用f1()

如果你想要那个语义(短路(,你需要使用b = b || f1();等等。 (如您所指出的:b ||= f1()是语法错误。


1 - 实际上,在无法观察到(在单线程程序中(f1()调用是否发生的情况下,理论上允许优化。 但是,您只能通过仔细检查 JIT 编译器发出的本机代码来检测优化。 只有当调用严格无副作用时,才会发生这种情况。

这更多的是关于布尔运算符和按位运算符之间的区别。

|=复合运算符是按位运算符,这意味着将计算这两个项。

您可以通过设置一个测试来轻松调试它,其中b被分配文本true,然后|=赋值到返回boolean值并在其中具有断点的方法。

断点将始终触发。

另一方面,"快捷方式"优化仅适用于布尔运算符:||&&

注意:这里有一些关于复合分配的规范,但我找不到|=分配的相关部分。

相关内容

  • 没有找到相关文章

最新更新