2010-01-11 6 views
15

logisch, if(!foo) und if(foo == false) sind gleichwertig. Wie sind sie in Java vertreten? Gibt es einen Unterschied zwischen den beiden nach der Kompilierung, entweder im Bytecode oder in der Performance? Ich konnte keine Antwort in der JLS finden und die Suche ergab viele Ergebnisse über = vs. == Tippfehler und ==/equals() Verhalten. (In diesem Fall behinderten die Symbole meine Suche; für zukünftige Sucher ist der Negationsoperator gleich falsch, gleich falsch, nicht Bedingung).Was ist der Leistungsunterschied zwischen if (! Foo) und if (foo == false) in Java?

Um die CW-Debatte abzuwenden: Diese Frage fragt nicht, welche Variante die Leute bevorzugen oder welche als besser angesehen wird. Ich interessiere mich für die Unterschiede in der Umsetzung der Sprache, also gibt es eine richtige Antwort. Ähnlich-but-not-quite-a-Betrogene: Difference between while (x = false) and while (!x) in Java?

EDIT:

Der allgemeine Konsens, dass ein guter Compiler diese auf dasselbe hinaus optimieren sollte zu sein scheint. Das macht Sinn und ist das, was ich vermutete, aber - um eine noch akademischere Frage zu stellen - ist dieses Verhalten eigentlich irgendwo vorgeschrieben, oder ist es "nur" das Vernünftige, was zu tun ist?

+0

Beachten Sie, dass dies compilerspezifisch ist. – danben

+1

Hier sind zwei Fragen. Der erste fragt, wie es in Java dargestellt wird (Bytecode). Die zweite fragt, ob es Unterschiede in der Leistung und im Bytecode gibt (ich nehme an, dass die Größe hier der relevante Faktor ist). –

+3

Jeder Compiler, der diese Optimierung nicht erkennt, wird es nicht sehr weit auf dem Markt machen;) –

Antwort

44

Die JLS würde das erforderliche Verhalten der Anweisungen angeben. Wie sie implementiert werden, ist jedoch ein Implementierungsdetail des Compilers und der JVM.

In der Praxis sollte jeder Compiler, der seinen Wert wert ist, denselben Bytecode für diese Anweisungen ausgeben. Und selbst wenn nicht, würde die JVM sie richtig optimieren.

Auch ein besserer Weg, dies zu beantworten, ist für sich selbst zu überprüfen, mit javap:

  1. eine Test.java Kompilieren mit folgendem Inhalt:

    class Test { 
        void equals(boolean f) { 
         if (f == false) {} 
        } 
        void not(boolean f) { 
         if (!f) {} 
        } 
    } 
    $ javac Test.java 
    
  2. De-fügen Sie hinzu:

    $ javap -c Test 
    Compiled from "Test.java" 
    class Test extends java.lang.Object{ 
    Test(); 
        Code: 
        0: aload_0 
        1: invokespecial #1; //Method java/lang/Object."<init>":()V 
        4: return 
    
    void equals(boolean); 
        Code: 
        0: iload_1 
        1: ifne 4 
        4: return 
    
    void not(boolean); 
        Code: 
        0: iload_1 
        1: ifne 4 
        4: return 
    
    } 
    

UPDATE: Ihre Frage zu der "akademischen" Frage beantworten. Wie oben erwähnt, beschäftigt sich die JLS nur mit dem Verhalten. Es gibt nichts im Standard, das tatsächlich angibt, wie es implementiert werden sollte (nun, JVMS bietet eine Menge Anleitung).

Solange der Compiler das gleiche identische Verhalten beibehält, kann der Compiler es anders implementieren, mit der Möglichkeit einer anderen Laufzeitleistung.

+0

Das nenne ich guten Willen! Herzlichen Glückwunsch für Ihre Geduld! –

+4

'javap -c' disassembliert, dekompiliert es nicht. –

+1

Schöne Antwort, danke. Das Erwähnen von Javap alleine reichte für eine +1, ich hatte noch nie davon gehört. – Pops

12

Der Compiler sollte intern auf den gleichen Code auflösen, so dass es keinen Unterschied gibt.

+0

Wie wäre es, es genauso zu zeigen, wie es nicht war. –

+5

Wie wäre es, eine freie Aussage ohne irgendeine Referenz, einen Beweis usw. zu aktualisieren (selbst wenn sie wahr ist). –

0

versuchen decompiling the byte code und sehen, wie anders der Code aussieht. Ich würde vermuten, dass die Kompilierung sie fast identisch auflösen würde und jeder kleine Unterschied würde zu einem vernachlässigbaren Leistungsunterschied führen.

+1

oder werfen Sie einen Blick auf den Byte-Code selbst http://stackoverflow.com/questions/800916/should-i-look-at-the-bytecode-that-is-produce-by-a-java-compiler – gingerbreadboy

0

OK, eine vollständigere Antwort:

Ich wäre sehr überrascht, wenn jeder Compiler verschiedene Bytecode für diese Variationen erzeugt. Für alle, die daran interessiert sind, sollte es einfach sein, einen Disassembler zu verwenden.

Vorausgesetzt, dass beide Ausdrücke (höchstwahrscheinlich) auf den gleichen Bytecode kompilieren, erwarte ich keinen Unterschied in der Größe oder Leistung.

0

Die JLS sagt, dass

der Ausdruck in ein, wenn Block ausgewertet wird, dann ist das Ergebnis des Ausdrucks In zu wahr

verglichen wird sowohl in dem nicht Fall und vergleichen Object Cases, ein Ausdruck muss evaluiert und dann mit true verglichen werden. Wenn Sie einen Wert überprüfen, anstatt einen Operator darauf auszuführen, kann es einen theoretischen Leistungsvorteil geben, da die Ausdruckbewertung zu einem Nein-Op wird.

Aber in diesem Fall würde ich erwarten, dass das JIT den gleichen Bytecode für beide Ausdrücke erzeugt.

0

Es sollte keinen Unterschied in dem für diese beiden Ergebnisse generierten Bytecode geben, und wenn dies der Fall ist, es sei denn, Sie erstellen Code für ein Gerät mit sehr begrenzten Ressourcen (in diesem Fall sollten Sie nicht in Java schreiben) vernachlässigbar und Sie sollten entscheiden, welche der beiden Möglichkeiten, diesen Code zu schreiben, eine offenere Lösung ist.

0

Nachdenken über Mikro-Optimierungen in fast allen Fällen eine Verschwendung von Zeit und führt in der falschen Art und Weise zu denken ...

+0

Siehe mein Kommentar im Thread der Frage. – Pops

0

Ich fragte eine ähnliche Frage in Bezug auf C++/VS2008.

Would VS2008 c++ compiler optimize the following if statement?

To = vs == Fehler in C++ zu vermeiden, würden Sie

if (NULL == ptr) { ... } 
if (false == boo) { ... } 
if (20 == num) { ... } 

usw.

Dies ist etwas weniger lesbar schreiben neigen, bis Sie sich daran gewöhnen.

Verwandte Themen