The two are semantically identical, and the compiler will generate the same code in both cases. If you're trying to intentionally include an empty loop body, {}
makes it more clear that it's on purpose rather than just a stray semicolon. You should always explicitly comment such cases, and it's usually better to rework your code to avoid a busy-wait loop altogether.
Any minor difference between ; or {} to represent a null statement?
-
04-08-2022 - |
题
I understand that the statement terminator symbol ;
, if used solitarily, represents a null statement. Also, "empty loop bodies" can be a useful programming construct, and are made using null statements.
Looking at the while statement below, on line #2, I decided to replace the terminating ;
symbol, with a pair of back-to-back {}
curly braces. The code compiled and ran OK. Does this mean that the Java compiler replaces an empty code block (represented by the "empty" {}
curly braces), with a ;
based null statement?
If Java does something slightly different, would the resulting bytecode be identical in both cases? (I'm sorry that I can't check this ATM. I'm new to Java, and I don't yet have the necessary knowledge to display and examine bytecode).
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.
解决方案
其他提示
The same byte-code will be generated in both cases.
I prefer to use { }
instead of ;
, the latter can sometime have a feeling of typo when it's used in for
and while
loops.
If I have this code:
while(i-- < j++);
System.out.println("Wild World");
I would think maybe it's a typo, ;
shouldn't be here.
But if I have:
while(i-- < j++) { }
System.out.println("Wild World");
I know there is a reason for that..
For good measure:
Building on the other two answers I put both pieces of code in an example as follows:
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.
}
}
and
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.
}
}
using javap -c I got the following bytecode:
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
}
and
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
}
They appear identical implying regardless of which way you choose, the compiler implements it exactly the same.
These are technically two different things. One is an empty block, and one is an empty statement.
while(...)
statement;
Java will interpret this as:
while(...)
{
statement;
}
which means that
while(...);
is while(...){;}
which is then while(...){}
My point:
While they produce equivalent bytecode(and are for all intents and purposes equivalent) they are really two different things, that both arrive at the same result by a couple of java rules. {}
is really not a null(or blank) statement. It's an empty block. While loops must be followed by a block, so a blank statement is wrapped into a block, then the blank statement removed.