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

其他提示

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.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top