2013-11-25 8 views
15

Ich verstehe, dass das Statement-Terminator-Symbol ;, wenn es nur solar verwendet wird, eine Null-Anweisung darstellt. Außerdem können "leere Schleifenkörper" ein nützliches Programmierungskonstrukt sein und werden unter Verwendung von NULL-Anweisungen erstellt.Jeder geringfügige Unterschied zwischen; oder {}, um eine Nullanweisung darzustellen?

Mit Blick auf die while-Anweisung unten, in Zeile # 2, entschied ich mich, das abschließende ; Symbol mit einem Paar Rücken an Rücken {} geschweiften Klammern zu ersetzen. Der Code kompiliert und lief OK. Bedeutet dies, dass der Java-Compiler einen leeren Codeblock (dargestellt durch die "leeren" {} geschweiften Klammern) mit einer ; basierten Nullanweisung ersetzt?

Wenn Java etwas etwas anderes macht, wäre der resultierende Bytecode in beiden Fällen identisch? (Es tut mir leid, dass ich diesen ATM nicht überprüfen kann. Ich bin neu in Java, und ich habe noch nicht das notwendige Wissen, um Bytecode anzuzeigen und zu untersuchen).

int i=0,j=100; 

// Either a terminating ; symbol or {} braces work to make an "empty loop body". 
while (++i < --j) {} 
System.out.println("The midpoint between 0 and 100 is " +i); // Midpoint is 50. 
+0

Ich benutze tatsächlich '{;}' Um den Block zu sehen, aber auch zu wissen, dass ich wirklich nichts in diesen Block legen wollte, und nicht nur die geschweiften Klammern erstellt, um später ausgefüllt zu werden. Dies ist jedoch meine eigene Sache und habe noch nie jemand anderes gesehen. – Cruncher

Antwort

18

Die beiden sind semantisch identisch, und der Compiler wird in beiden Fällen den gleichen Code generieren. Wenn Sie versuchen, einen leeren Schleifenkörper absichtlich einzubeziehen, macht {} es deutlicher, dass es absichtlich und nicht nur ein streunendes Semikolon ist. Sie sollten solche Fälle immer explizit kommentieren, und es ist normalerweise besser, Ihren Code zu überarbeiten, um eine Busy-Wait-Schleife zu vermeiden.

+2

Darüber hinaus machen die Klammern die Absicht IMO klarer. Auch bei richtiger Einrückung, etwas wie 'while (...); a ++; '(stellen Sie sich einen Zeilenumbruch nach dem ersten' '' vor - tut mir leid, kann das nicht in Kommentaren tun) kann leicht als inkrementieren 'a' innerhalb der Schleife falsch gelesen werden. Dies kann einen Leser des Codes verwirren, oder noch schlimmer: jemand könnte mitkommen und das '' 'nach der Weile entfernen, weil sie daran denken, was du meintest. – CompuChip

16

In beiden Fällen wird der gleiche Bytecode generiert.

Ich ziehe { } statt ; zu verwenden, kann diese irgendwann ein Gefühl von Typo hat, wenn es in for und while Schleifen verwendet wird.

Wenn ich diesen Code haben:

while(i-- < j++); 
System.out.println("Wild World"); 

Ich würde denken, vielleicht ist es ein Tippfehler, ; sollte nicht hier sein.

Aber wenn ich habe:

while(i-- < j++) { } 
System.out.println("Wild World"); 

Ich weiß, dass es einen Grund dafür ist ..

7

Für eine gute Maßnahme:

Aufbauend auf den beiden anderen Antworten habe ich die beiden Teile des Codes in einem Beispiel wie folgt:

public class SO { 
public static void main(String[] args){ 
    int i=0,j=100; 

// Either a terminating ; symbol or {} braces work to make an "empty loop body". 
while (++i < --j) {} 
System.out.println("The midpoint between 0 and 100 is " +i); // Midpoint is 50. 
} 
} 

und

public class SO2 { 
public static void main(String[] args){ 
    int i=0,j=100; 

// Either a terminating ; symbol or {} braces work to make an "empty loop body". 
while (++i < --j) ; 
System.out.println("The midpoint between 0 and 100 is " +i); // Midpoint is 50. 
} 
} 

javap mit -c ich folgende Bytecode bekam:

Compiled from "SO.java" 
public class SO { 
    public SO(); 
    Code: 
     0: aload_0 
     1: invokespecial #1     // Method java/lang/Object."<init>":()V 
     4: return 

    public static void main(java.lang.String[]); 
Code: 
    0: iconst_0 
    1: istore_1 
    2: bipush  100 
    4: istore_2 
    5: iinc   1, 1 
    8: iload_1 
    9: iinc   2, -1 
    12: iload_2 
    13: if_icmpge  19 
    16: goto   5 
    19: getstatic  #2     // Field java/lang/System.out:Ljava/io/PrintStream; 
    22: new   #3     // class java/lang/StringBuilder 
    25: dup 
    26: invokespecial #4     // Method java/lang/StringBuilder."<init>":()V 
    29: ldc   #5     // String The midpoint between 0 and 100 is 
    31: invokevirtual #6     // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 
    34: iload_1 
    35: invokevirtual #7     // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder; 
    38: invokevirtual #8     // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 
    41: invokevirtual #9     // Method java/io/PrintStream.println:(Ljava/lang/String;)V 
    44: return 
} 

und

Compiled from "SO2.java" 
public class SO2 { 
    public SO2(); 
    Code: 
     0: aload_0 
     1: invokespecial #1     // Method java/lang/Object."<init>":()V 
     4: return 

    public static void main(java.lang.String[]); 
Code: 
    0: iconst_0 
    1: istore_1 
    2: bipush  100 
    4: istore_2 
    5: iinc   1, 1 
    8: iload_1 
    9: iinc   2, -1 
    12: iload_2 
    13: if_icmpge  19 
    16: goto   5 
    19: getstatic  #2     // Field java/lang/System.out:Ljava/io/PrintStream; 
    22: new   #3     // class java/lang/StringBuilder 
    25: dup 
    26: invokespecial #4     // Method java/lang/StringBuilder."<init>":()V 
    29: ldc   #5     // String The midpoint between 0 and 100 is 
    31: invokevirtual #6     // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 
    34: iload_1 
    35: invokevirtual #7     // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder; 
    38: invokevirtual #8     // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 
    41: invokevirtual #9     // Method java/io/PrintStream.println:(Ljava/lang/String;)V 
    44: return 
} 

Sie scheinen identisch Implizieren unabhängig davon, welche Art und Weise Sie sich entscheiden, implementiert der Compiler es genau das gleiche.

3

Das sind technisch zwei verschiedene Dinge. Einer ist ein leerer Block und einer ist eine leere Aussage.

while(...) 
    statement; 

Java interpretiert dies als:

while(...) 
{ 
    statement; 
} 

was bedeutet, dass

while(...);while(...){;} ist, die dann while(...){} ist

Mein Punkt:

Während sie gleichwertig Bytecode erzeugen (und sind in jeder Hinsicht äquivalent) sie sind wirklich zwei verschiedene Dinge, die beide durch ein paar Java-Regeln zum selben Ergebnis kommen. {} ist wirklich keine leere (oder leere) Aussage. Es ist ein leerer Block. Auf While-Schleifen muss ein Block folgen, also wird eine leere Anweisung in einen Block eingeschlossen, dann wird die leere Anweisung entfernt.

Verwandte Themen