2009-11-25 55 views
101

我的問題可能是非常基本的,但我認爲它值得去問。我有以下代碼:&&(AND)and || (或)在IF陳述

if(!partialHits.get(req_nr).containsKey(z) || partialHits.get(req_nr).get(z) < tmpmap.get(z)){ 
    partialHits.get(z).put(z, tmpmap.get(z)); 
} 

其中partialHits是一個HashMap。如果第一個陳述是真的會發生什麼? Java仍會檢查第二條語句嗎?因爲爲了使第一條語句成立,HashMap不應該包含給定的鍵,所以如果第二條語句被選中,我會得到NullPointerException
那麼簡單的話,如果我們有以下代碼

if(a && b) 
if(a || b) 

將Java的檢查b如果a是在第一種情況下假,如果a在第二種情況下是真的嗎?

回答

158

不,它不會被評估。這非常有用。就像你需要測試,如果一個字符串不爲空或爲空,你可以寫:

if (str != null && !str.isEmpty()) { 
    doSomethingWith(str.charAt(0)); 
} 

,或者倒過來

if (str == null || str.isEmpty()) { 
    complainAboutUnusableString(); 
} else { 
    doSomethingWith(str.charAt(0)); 
} 

如果我們有沒有「短路」 Java,我們會在上面的代碼行中收到很多NullPointerExceptions。

+0

是否存在按位比較以便您可以評估這兩個表達式?即如果(str!= null | str.isEmpty())? (當然這不是一個實際的例子,實際上它很愚蠢,但你明白了) – Kezzer

+5

只要表達式沒有副作用,短路語義在邏輯上就等同於完整的評估。也就是說,如果A是真的,你知道A || B是真的,而不必評估B.只有當表達式有副作用時,纔會有所作爲。至於其他操作符,您可以使用'*'和'+'作爲邏輯'和'和'或'; ((A1→0)×(B1→0))== 1「,((A1→0)+(B1→0))> 0。你甚至可以做'xor':'((A?1:0)+(B?1:0))== 1'。 – outis

+1

@Kezzer:是真的按位比較嗎?我認爲它是一個布爾邏輯運算符。它與'按位'(整數)運算符不同,儘管它們具有相同的符號... –

27

不,它不會被檢查。這種行爲被稱爲short-circuit evaluation,並且是許多語言(包括Java)的一項功能。

+2

@Azimuth:非常歡迎。如果你不知道什麼,解決問題的最好方法就是問。 –

5

不,如果a爲真(在or測試中),b將不會被測試,因爲無論b表達式的值如何,測試的結果都將始終爲真。

做一個簡單的測試:

if (true || ((String) null).equals("foobar")) { 
    ... 
} 

拋出NullPointerException

4

不,不會,Java一旦知道結果就會短路並停止評估。

18

這裏的所有答案都很棒,但僅僅爲了說明這些來自哪裏,對於像這樣的問題,最好轉到源代碼:Java語言規範。

Section 15:23, Conditional-And operator (&&),說:

的& &操作就像&(§15.22.2),但評估其右邊的操作數只有在其左側操作數的值是true。 [...]在運行時,如果結果值爲假,則條件表達式和表達式的值爲假,並且右邊的操作數表達式不被評估。如果左側操作數的值爲真,則右側表達式將被求值,結果值將成爲條件表達式和表達式的值。因此,& &計算與布爾操作數上的&相同的結果。它的區別僅在於右邊的操作數表達式是有條件地而不是總是被評估的。

同樣,Section 15:24, Conditional-Or operator (||),說:

的||運算符就像| (§15.22.2),但只有在其左側操作數的值爲假時才評估其右側操作數。 [...]在運行時,首先評估左邊的操作數表達式; [...]如果結果值爲真,則條件或表達式的值爲true,並且不評估右側操作數表達式。如果左側操作數的值爲假,則評估右側表達式; [...]結果值變成條件或表達式的值。因此,||計算與|相同的結果在布爾操作數或布爾操作數上。它的區別僅在於右邊的操作數表達式是有條件地而不是總是被評估的。

有點重複,也許,但他們確切地如何工作的最好證實。 ?

int x = (y == null) ? 0 : y.getFoo(); 

沒有一個NullPointerException:同樣條件運算符(:)僅如果值是如果這是真的假的,右半部分),允許像使用表達式計算相應的「半壁江山」(左半部分。

4

是的,布爾表達式的短路評估是所有類C系列中的默認行爲。

一個有趣的事實是,Java還使用了&|邏輯操作數(它們是超載,具有int類型,他們都期望位運算),以評估在表達,當你需要它也是有用的所有條款副作用。

+0

這很有意思,例如:給定一個返回布爾值的方法changeData(data),則: if(a.changeData(data)|| b.changeData(data)){doSomething(); } 不b上執行changeData如果a.changeData()返回true,但 如果(a.changeData(數據)| b.changeData(數據)){DoSomething的()} 執行changeData()上無論是a還是b,即使在返回的true上調用。 – Sampisa

51

Java有5個不同的布爾比較運營商:&,& &,|,||^

&和& &是 「和」 的運營商,|和|| 「或」操作符,^是「xor」

在檢查參數值之前,單個參數將檢查每個參數,而不考慮值。 雙擊將會首先檢查左邊的參數及其值,如果true||)或false&&)會保持第二個參數不變。 聲音完整?一個簡單的例子應該清楚:

鑑於所有的例子:

String aString = null; 

AND:

if (aString != null & aString.equals("lala")) 

兩個參數評估工作完成之前進行檢查和一個NullPointerException將被拋出爲第二個參數。

if (aString != null && aString.equals("lala")) 

第一個參數被選中並返回false,所以第二放慢參數將不檢查,因爲結果是false反正。對於OR

相同:

if (aString == null | !aString.equals("lala")) 

會引發NullPointerException異常了。

if (aString == null || !aString.equals("lala")) 

第一個參數被選中並返回true,所以第二放慢參數將不檢查,因爲結果是true反正。

XOR無法優化,因爲它取決於兩個參數。

+2

「Java有4種不同的布爾比較運算符:&,&&,|,||」...您忘記了'^'(xor)。 – aioobe

+0

哦,我不知道它也檢查布爾值布爾值。到目前爲止,僅用於位掩碼。 – Hardcoded

0

這可以回到&和&之間的基本區別&,| |和||

順便說一句,你多次執行相同的任務。不確定效率是否是一個問題。你可以刪除一些重複。

Z z2 = partialHits.get(req_nr).get(z); // assuming a value cannout be null. 
Z z3 = tmpmap.get(z); // assuming z3 cannot be null. 
if(z2 == null || z2 < z3){ 
    partialHits.get(z).put(z, z3); 
} 
4

此處的短路表示不會評估第二個條件。

如果(A & & B)將導致短路,如果A是假的。

如果(A & & B)將而不是導致短路如果A爲真。

如果(A || B)將導致短路,如果A爲真。

如果(A || B)將而不是如果A爲False導致短路。