Verwirrendes Beispiel zu '&&' und '||' Vorrang

7

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:

%Vor%

Ausgaben:

%Vor%

Das beweist, dass nur a1 < a2 ausgewertet wird. Können Sie erklären, warum dies der Fall ist?

    
AbdelRahmane 16.10.2016, 15:09
quelle

4 Antworten

13

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 || :

    %Vor%

    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:

    %Vor%

    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:

%Vor% %Vor% %Vor%

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.

    
Li357 16.10.2016, 15:11
quelle
6

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

ausgewertet     
SamTebbs33 16.10.2016 15:11
quelle
5

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:

%Vor%

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.

    
scottb 16.10.2016 16:03
quelle
3

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 || .

    
Eran 16.10.2016 15:13
quelle