[英]Why does Java not optimize |= assignments?
對於此示例, t*()
始終返回true,其中f*()
始終返回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(但值得注意的是,在1999年之前C沒有明確的布爾類型) 。
我仍然想知道為什么不進行優化?
因為這會違反JLS。
該聲明
b |= f1();
相當於
b = (boolean)(b | f1());
在上面,JLS 要求 b | f1()
b | f1()
的評估如下:
b
的值。 f1()
並捕獲結果值 |
運算符到兩個值。 該JLS 不允許編譯器跳過調用f1()
如果b
是true
1。
如果你想要語義(短路),你需要使用b = b || f1();
b = b || f1();
等等。 (如您所述: b ||= f1()
是語法錯誤。)
1 - 實際上,在無法觀察(在單線程程序中) f1()
調用已發生或未發生的情況下,理論上允許進行優化。 但是您只能通過仔細檢查JIT編譯器發出的本機代碼來檢測優化。 它只有在呼叫嚴格無副作用時才會發生。
這更多地是關於布爾運算符和位運算符之間的區別。
|=
復合運算符是一個按位運算符,意味着將對這兩個項進行求值。
你可以通過設置一個測試來輕松地調試它,其中b
被賦值為literal true
,然后是|=
賦值給返回boolean
值的方法,並且在其中有一個斷點。
斷點將始終觸發。
另一方面,“快捷方式”優化僅適用於布爾運算符: ||
和&&
。
注意: 這里有關於復合賦值的一些規范,但我找不到|=
賦值的相關部分。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.