Ich habe die Priorität zwischen &&
und ||
getestet und ich hatte ein Beispiel, das verwirrend war. In Java hat &&
eine höhere Operatorpriorität als der Operator ||
.
Also, wenn wir diese 3 Ausdrücke haben:
%Vor%Es sollte wie folgt bewertet werden:
%Vor% Also expr2 && expr3
sollte vor expr1
ausgewertet werden. Dieses Beispiel:
Ausgaben:
%Vor% Das beweist, dass nur a1 < a2
ausgewertet wird.
Können Sie erklären, warum dies der Fall ist?
Der Ausdruck ist kurzgeschlossen . Von der Verbindung:
Wenn das erste Argument der AND-Funktion false ergibt, muss der Gesamtwert false sein. und wenn das erste Argument der OR-Funktion als wahr ausgewertet wird, muss der Gesamtwert wahr sein.
Er sieht, dass der Rest der Bedingung keine Rolle spielt, weil einer der Operanden von ||
bereits wahr ist (10 & lt; 20). Wenn einer der Operanden wahr ist, dann ist es wahr, egal was der Rest der Bedingung ist.
Sie können bitwise &
und |
verwenden, um dies zu verhindern.
Aber das (expr2 & amp; & amp; expr3) sollte vor expr1 ausgewertet werden, nein?
Nein. Sie müssen die Konzepte Vorrang und Bewertungsreihenfolge trennen.
Vorrang : Diktiert die Klammerung eines Ausdrucks, nicht die Reihenfolge, in der ein Ausdruck ausgewertet wird. Für ein Beispiel:
%Vor% Wird in Klammern gesetzt, da &&
eine höhere Priorität hat als ||
:
Dies bedeutet nicht, dass Sachen in Klammern zuerst in Javas Fall ausgewertet werden. Der Vorrang stellt nur klar, was die Operanden eines Operators sind, in diesem Fall false
und false
, wo in dieser Fall:
Die Operanden für &&
sind true
und false
, nicht false
und false
.
Auswertungsreihenfolge : Beschreibt, in welcher Reihenfolge jeder Operand ausgewertet und der Operator angewendet wird und manchmal sprachspezifisch ist. Dies legt fest, wie ein Ausdruck im Gegensatz zur Priorität ausgewertet wird.
In diesem Fall, Ihr Beispiel:
%Vor%Wie bereits erwähnt, wird dies aufgrund der Priorität:
%Vor%Aber Java hat im Gegensatz zu C ++, JavaScript oder einer Reihe anderer Sprachen eine strikte Links-zu-Rechts-Bewertung. Nach der Java-Sprachspezifikation :
15.7. Bewertungsreihenfolge
Die Programmiersprache Java garantiert, dass die Operanden von Operatoren in einer bestimmten Auswertungsreihenfolge ausgewertet werden, nämlich von links nach rechts.
15.7.1. Zuerst den linken Operanden auswerten
Der linke Operand eines binären Operators scheint vollständig ausgewertet zu sein, bevor ein Teil des rechten Operanden ausgewertet wird.
Also, wenn du hast:
%Vor% Java wertet zuerst den linken Operanden aus, der sich als true
herausstellt. Dann schließt der ganze Zustand kurz. Der rechte Operand von ||
in den Klammern wird überhaupt nicht ausgewertet. Das gleiche gilt für Ihr anderes Beispiel:
Nehmen Sie ein komplexeres Beispiel:
%Vor%Aufgrund der Priorität wird es:
%Vor%Dann beginnt die Auswertung von links nach rechts:
%Vor% %Vor% %Vor% Somit wird der gesamte Ausdruck als true
ausgewertet. Der ganze Ausdruck wurde den ganzen Weg von links nach rechts ausgewertet. Die Priorität diktierte nur die Operanden eines Operators über die Klammerung, nicht die Bewertungsreihenfolge.
Weitere Lesungen im Eric Lipperts erläuternden Artikel auf Rangfolge vs Assoziativität vs Bewertungsreihenfolge wie in Daniel Pryden erwähnt, Es räumt viel Verwirrung auf.
Das Wichtigste ist, dass Vorrang nicht vorschreibt, in was ein Ausdruck ausgewertet wird. Es gibt nur vor, wie ein Ausdruck in Klammern gesetzt werden soll. Bewertungsreihenfolge hingegen sagt uns genau, wie ein Ausdruck bewertet wird, und im Fall von Java ist immer von links nach rechts.
Die erste Zeile gibt true
aus, weil der Operator ||
kurzgeschlossen wurde.
a1 < a2
ist wahr und daher muss der Rest des booleschen Ausdrucks nicht ausgewertet werden und true
wird zurückgegeben.
expr2 sollte vor expr1
ausgewertet werden
ist falsch, da sich die Vorrangstellung des Operators auf die Struktur des Ausdrucks und nicht auf die Evaluierungsreihenfolge (in den meisten Fällen) auswirkt. Wenn Sie den Ausdruck so umordnen würden, dass er (expr2 && expr3) || expr1
ist, dann wird ja expr2
vor expr1
Vorrang:
%Vor%Um den korrekten Wert gemäß den Rangregeln zu erhalten, muss der Compiler dies logisch wie folgt bewerten:
%Vor% Das spricht dafür, dass b && c
ausgewertet werden muss, bevor result
berechnet werden kann. In der Booleschen Algebra ist es jedoch möglich, Ausdrücke zu schreiben, deren Ergebnisse nicht von allen Operanden abhängen. Diese Tatsache wird ausgenutzt, um eine Compiler-Optimierung namens short circuitring zu ermöglichen.
Kurzschluss:
Für jeden booleschen Ausdruck:
%Vor% Das Ergebnis hängt nicht von b
ab, wenn a
zu true
ausgewertet wird. Wenn a
true
ist, ist es egal, ob b
als wahr oder falsch ausgewertet wird. Aus diesem Grund führt der Compiler Folgendes aus:
als ob es geschrieben worden wäre:
%Vor% Beachten Sie, dass auf diese Weise die Präzedenzregeln eingehalten werden. Der Ausdruck wird nicht als (a || b) && c
ausgewertet. Da das Gesamtergebnis des Ausdrucks nicht von (b && c)
abhängt, wenn a
wahr ist, wird b && c
einfach nie ausgewertet.
Das ist eine gute Sache. Kurzschlüsse erlauben es Ihnen, korrekte Programme zu schreiben, wenn die Korrektheit eines Operanden von der Korrektheit eines anderen abhängt. Zum Beispiel:
%Vor% Ohne Kurzschlussauswertung könnte der boolesche Ausdruck einen NullPointerException
ausgeben. Aufgrund der Kurzschlußauswertung kann dieser Ausdruck jedoch, wie beschrieben, niemals NullPointerException
werfen.
Kurzschlüsse können auch als Leistungsoptimierung verwendet werden. Wenn die Auswertung eines Operanden extrem teuer ist, kann die Auswertung eines anderen zuerst die Ausführungszeit einsparen, die benötigt wird, um einen Operanden auszuwerten, dessen Wert das Endergebnis des gesamten Ausdrucks nicht beeinflusst.
Auch wenn Sie explizite Klammern wie in
verwenden %Vor% expr1
wird zuerst ausgewertet, da die Operanden von Operatoren von links nach rechts ausgewertet werden. Da ||
ein kurzgeschlossener Operator ist, wird der zweite Operand ( (expr2 && expr3)
in Ihrem Fall) nur ausgewertet, wenn expr1
false
ist.
Wenn Sie die Klammern entfernen, kommt die Operatorpriorität nur ins Spiel, wenn expr1
falsch ist. In diesem Fall wird der Operand &&
vor dem Operator ||
ausgewertet und sein Wert ist der zweite Operand des Operators ||
.
Tags und Links java java-7 operator-precedence