&& (UND) und || (ODER) in IF-Anweisungen

137

Ich habe folgenden Code:

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

Wo partialHitsist eine HashMap?
Was passiert, wenn die erste Aussage wahr ist? Wird Java die zweite Anweisung noch überprüfen? Da die erste Anweisung wahr sein soll, sollte die HashMap nicht den angegebenen Schlüssel enthalten. Wenn also die zweite Anweisung aktiviert ist, erhalte ich NullPointerException.
Also in einfachen Worten, wenn wir den folgenden Code haben

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

Würde Java prüfen, bob aes im ersten Fall falsch ist und ob aes im zweiten Fall wahr ist?

Azimut
quelle

Antworten:

202

Nein, es wird nicht ausgewertet. Und das ist sehr nützlich. Wenn Sie beispielsweise testen müssen, ob ein String nicht null oder leer ist, können Sie Folgendes schreiben:

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

oder umgekehrt

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

Wenn wir in Java keine Kurzschlüsse hätten, würden wir in den obigen Codezeilen viele NullPointerExceptions erhalten.

Andreas Dolk
quelle
Gibt es bitweise Vergleiche, damit Sie beide Ausdrücke auswerten können ? dh wenn (str! = null | str.isEmpty ())? (Natürlich ist dies kein praktisches Beispiel, tatsächlich ist es dumm, aber Sie bekommen die Idee)
Kezzer
5
Solange die Ausdrücke keine Nebenwirkungen haben, entspricht die Kurzschlusssemantik logischerweise einer vollständigen Auswertung. Das heißt, wenn A wahr ist, wissen Sie, dass A || B wahr ist, ohne B bewerten zu müssen. Das einzige Mal, wenn es einen Unterschied macht, ist, wenn ein Ausdruck Nebenwirkungen hat. Wie bei anderen Operatoren können Sie *und +als logisches andund or; ((A?1:0) * (B?1:0)) == 1, ((A?1:0) + (B?1:0)) > 0. Sie können sogar tun xor: ((A?1:0) + (B?1:0)) == 1.
Outis
1
@ Kezzer: Ist das wirklich ein bitweiser Vergleich? Ich denke, es ist ein boolean(logischer) Operator. Es ist anders als der bitwise(ganzzahlige) Operator, obwohl es das gleiche Symbol hat ...
user85421
4
Ein praktischer Trick, wenn Sie zwischen '&&' und '||' wechseln möchten. Ausdrücke sollen den gesamten Ausdruck negieren, so dass: !(str != null && !str.isEmpty()) wird: (str !(!=) null !(&&) !(!)str.isEmpty()) und dann: (str == null || str.isEmpty()) weil: !(!=) is == !(&&) is || !(!) eliminates itself andere hilfreiche Negationen sind: !(<) is >= !(>) is <= und umgekehrt
egallardo
68

Java hat 5 verschiedene boolesche Vergleichsoperatoren: &, &&, |, ||, ^

& und && sind "und" Operatoren, | und || "oder" Operatoren, ^ ist "xor"

Die einzelnen prüfen jeden Parameter, unabhängig von den Werten, bevor sie die Werte der Parameter prüfen. Die doppelten überprüfen zuerst den linken Parameter und seinen Wert und wenn true( ||) oder false( &&), lassen Sie den zweiten unberührt. Sound zusammengestellt? Ein einfaches Beispiel sollte deutlich machen:

Für alle Beispiele angegeben:

 String aString = null;

UND:

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

Beide Parameter werden vor Abschluss der Auswertung überprüft und für den zweiten Parameter wird eine NullPointerException ausgelöst.

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

Der erste Parameter wird überprüft und es wird zurückgegeben false, sodass der zweite Parameter nicht überprüft wird, da das Ergebnis falsesowieso ist.

Gleiches gilt für OR:

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

Löst auch eine NullPointerException aus.

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

Der erste Parameter wird überprüft und es wird zurückgegeben true, sodass der zweite Parameter nicht überprüft wird, da das Ergebnis truesowieso ist.

XOR kann nicht optimiert werden, da es von beiden Parametern abhängt.

Hardcodiert
quelle
3
"Java hat 4 verschiedene boolesche Vergleichsoperatoren: &, &&, |, ||" ... Sie vergessen ^(xor).
Aioobe
Oh, ich wusste nicht, dass es auch boolesche boolesche Werte überprüft. Bisher nur für Bitmasken verwendet.
Hardcoded
27

Nein, es wird nicht überprüft. Dieses Verhalten wird als Kurzschlussauswertung bezeichnet und ist in vielen Sprachen, einschließlich Java, eine Funktion.

Peter van der Heijden
quelle
20

Alle Antworten hier sind großartig, aber um zu veranschaulichen, woher dies kommt, ist es für Fragen wie diese gut, zur Quelle zu gehen: der Java-Sprachspezifikation.

In Abschnitt 15:23, Bedingter Und Operator (&&) , heißt es:

Der Operator && ist wie & (§15.22.2), wertet jedoch seinen rechten Operanden nur aus, wenn der Wert seines linken Operanden wahr ist. [...] Zur Laufzeit wird der linke Operandenausdruck zuerst ausgewertet, [...] wenn der resultierende Wert falsch ist, der Wert des Bedingungs- und Ausdrucks falsch ist und der rechte Operandenausdruck nicht ausgewertet wird . Wenn der Wert des linken Operanden wahr ist, wird der rechte Ausdruck ausgewertet, [...] der resultierende Wert wird zum Wert des Bedingungs- und Ausdrucks. Somit berechnet && das gleiche Ergebnis wie & für boolesche Operanden. Es unterscheidet sich nur dadurch, dass der Ausdruck des rechten Operanden eher bedingt als immer ausgewertet wird.

In ähnlicher Weise heißt es in Abschnitt 15:24, Bedingter-Oder-Operator (||) :

Die || Operator ist wie | (§15.22.2), wertet jedoch seinen rechten Operanden nur aus, wenn der Wert seines linken Operanden falsch ist. [...] Zur Laufzeit wird zuerst der linke Operandenausdruck ausgewertet. [...] Wenn der resultierende Wert wahr ist, ist der Wert des Bedingungs- oder Ausdrucks wahr und der Ausdruck des rechten Operanden wird nicht ausgewertet. Wenn der Wert des linken Operanden falsch ist, wird der rechte Ausdruck ausgewertet. [...] Der resultierende Wert wird zum Wert des Bedingungs- oder Ausdrucks. Also || berechnet das gleiche Ergebnis wie | auf booleschen oder booleschen Operanden. Es unterscheidet sich nur dadurch, dass der Ausdruck des rechten Operanden eher bedingt als immer ausgewertet wird.

Ein bisschen repetitiv vielleicht, aber die beste Bestätigung dafür, wie sie genau funktionieren. In ähnlicher Weise wertet der bedingte Operator (? :) nur die entsprechende 'Hälfte' aus (linke Hälfte, wenn der Wert wahr ist, rechte Hälfte, wenn er falsch ist) und erlaubt die Verwendung von Ausdrücken wie:

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

ohne eine NullPointerException.

Cowan
quelle
6

Nein, wenn a wahr ist (in einem orTest), wird b nicht getestet, da das Ergebnis des Tests immer wahr ist, unabhängig vom Wert des Ausdrucks b.

Machen Sie einen einfachen Test:

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

wird nicht werfen ein NullPointerException!

Romain Linsolas
quelle
6

Kurzschluss bedeutet hier, dass die zweite Bedingung nicht ausgewertet wird.

Wenn (A && B) zu einem Kurzschluss führt, wenn A falsch ist.

Wenn (A && B) nicht zu einem Kurzschluss führt, wenn A wahr ist.

Wenn (A || B) zu einem Kurzschluss führt, wenn A True ist.

Wenn (A || B) nicht zu einem Kurzschluss führt, wenn A falsch ist.

user3211238
quelle
4

Nein, Java wird kurzschließen und die Auswertung beenden, sobald das Ergebnis bekannt ist.

Abyx
quelle
4

Ja, die Kurzschlussauswertung für boolesche Ausdrücke ist das Standardverhalten in der gesamten C-ähnlichen Familie.

Eine interessante Tatsache ist, dass Java auch die &und |als logische Operanden verwendet (sie sind überladen, mit intTypen sind sie die erwarteten bitweisen Operationen), um alle Begriffe im Ausdruck auszuwerten, was auch nützlich ist, wenn Sie die Nebenwirkungen benötigen.

fortran
quelle
Es ist interessant, sich daran zu erinnern: zB bei einer Methode changeData (Daten), die einen Booleschen Wert zurückgibt, dann: if (a.changeData (Daten) || b.changeData (Daten)) {doSomething (); } führt changeData nicht auf b aus, wenn a.changeData () true zurückgibt, sondern wenn (a.changeData (data) | b.changeData (data)) {doSomething ()} changeData () sowohl auf a als auch auf b ausführt wenn derjenige, der auf einem zurückgegebenen true aufgerufen wurde.
Sampisa
0

Dies geht zurück auf den grundlegenden Unterschied zwischen & und &&, | und ||

Übrigens führen Sie die gleichen Aufgaben oft aus. Ich bin mir nicht sicher, ob Effizienz ein Problem ist. Sie könnten einige der Duplikate entfernen.

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);   
} 
Peter Lawrey
quelle