Java为什么不优化| =分配?

时间:2018-10-03 13:24:40

标签: java binary-operators conditional-execution

在此示例中,

t*()始终返回true,而f*()始终返回false。

假设我们有以下表达式

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

如果是这种情况,那么JVM会优化执行并仅执行f1()t1(),因为不管f2()t2()的结果如何,JVM都会“理解”满足输入if语句的要求,因此不需要进一步的计算。

我正在编写这样的代码:

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

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

我进行了一些测试,似乎所有的测试都正确执行了(这是期望的行为),但是我仍然想知道为什么没有对其进行优化?可能是正确的,并且JVM理解B为真后,对其上的任何b操作都不会更改其值。

3 个答案:

答案 0 :(得分:4)

由于JLS §15.26.2. Compound Assignment Operators需要对右侧表达式进行求值,因此无法优化调用。

  

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

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

  •   
  • ...

  •   

从历史上看,short-circuiting有条件(&&||)但不是按位(&|)运算符的传统至少可以追溯到C (但值得注意的是C直到1999年才具有显式的布尔类型)。

答案 1 :(得分:3)

  

我仍然想知道为什么没有对它进行优化?

因为这将违反JLS。

声明

b |= f1();

等效于

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

在上面,JLS 要求b | f1()进行如下评估:

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

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

如果要使用这种语义(短路),则需要使用b = b || f1();,依此类推。 (如您所述:b ||= f1()是语法错误。)


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

答案 2 :(得分:1)

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

|=复合运算符是按位运算符,表示两个项都被求值。

您可以通过设置将b分配给文字true的测试,然后对返回值|=的方法进行boolean的分配,来轻松调试此问题。有一个断点。

断点将始终触发。

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

注意:关于复合作业here的一些规范,但是我找不到|=作业中的相关部分。