Any minor difference between ; or {} to represent a null statement?
Asked Answered
B

4

15

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.
Batten answered 25/11, 2013 at 11:51 Comment(1)
I actually use {;} To see the block, but also to know that I really meant to put nothing in that block, and didn't just create the braces to be filled in later. This is my own thing though, and have never seen anyone else do it.Mandi
D
18

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.

Dillingham answered 25/11, 2013 at 11:54 Comment(1)
In addition, the braces make the intent clearer IMO. Even with proper indentation, something like while(...); a++; (imagine a line break after the first ; - sorry, can't do that in comments) can easily be misread as incrementing a inside the loop. This may confuse a reader of the code, or worse: someone might come along and remove the ; after the while because they think that is what you meant.Plummet
M
16

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

Marinna answered 25/11, 2013 at 11:54 Comment(0)
P
7

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.

Pterosaur answered 25/11, 2013 at 12:13 Comment(0)
M
3

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.

Mandi answered 25/11, 2013 at 18:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.