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
操作都不会更改其值。
答案 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()
进行如下评估:
b
的值。f1()
并捕获结果值|
运算符应用于两个值。如果f1()
为b
1 ,则JLS 不允许允许编译器跳过调用true
。
如果要使用这种语义(短路),则需要使用b = b || f1();
,依此类推。 (如您所述:b ||= f1()
是语法错误。)
1-实际上,在无法观察(在单线程程序中)发生f1()
调用的情况下,从理论上讲,这种优化是允许的。但是您只能通过仔细检查JIT编译器发出的本机代码来检测优化。只有在通话完全没有副作用的情况下,它才会发生。
答案 2 :(得分:1)
这更多地是关于布尔运算符和按位运算符之间的区别。
|=
复合运算符是按位运算符,表示两个项都被求值。
您可以通过设置将b
分配给文字true
的测试,然后对返回值|=
的方法进行boolean
的分配,来轻松调试此问题。有一个断点。
断点将始终触发。
另一方面,“快捷方式”优化仅适用于布尔运算符:||
和&&
。
注意:关于复合作业here的一些规范,但是我找不到|=
作业中的相关部分。