Любая незначительная разница между; или {} для представления нулевого оператора?

Я понимаю, что символ терминатора термина ;, если он используется в одиночку, представляет собой нулевой оператор. Кроме того, "пустые тела цикла" могут быть полезной конструкцией программирования и выполняются с использованием нулевых операторов.

Глядя на приведенное ниже выражение, в строке 2, я решил заменить завершающий символ ; на пару фигурных скобок {}. Код скомпилирован и работает нормально. Означает ли это, что компилятор Java заменяет пустой блок кода (представленный "пустым" <фигурным скобками {}) с нулевым утверждением ;?

Если Java делает что-то немного другое, будет ли полученный байт-код одинаковым в обоих случаях? (Мне жаль, что я не могу проверить этот банкомат. Я новичок в Java, и у меня пока нет необходимых знаний для отображения и изучения байт-кода).

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.

Ответ 1

Эти два семантически идентичны, и компилятор будет генерировать один и тот же код в обоих случаях. Если вы пытаетесь преднамеренно включить тело пустого цикла, {} делает его более понятным, чем это намеренно, а не просто слюной точкой с запятой. Вы всегда должны явно комментировать такие случаи, и обычно лучше переделать свой код, чтобы избежать цикла "занятый-ждать".

Ответ 2

В обоих случаях будет создан тот же байт-код.

Я предпочитаю использовать { } вместо ;, последний может когда-то иметь опечатку, когда он используется в циклах for и while.

Если у меня есть этот код:

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

Я думаю, может быть, это опечатка, ; здесь не должно быть.

Но если у меня есть:

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

Я знаю, что для этого есть причина.

Ответ 3

Для хорошей меры:

Основываясь на двух других ответах, я помещаю обе части кода в пример следующим образом:

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

и

 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 -c Я получил следующий байт-код:

    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
}

и

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
}

Они кажутся одинаковыми, подразумевая независимо от того, каким образом вы выбираете, компилятор реализует его точно так же.

Ответ 4

Это технически две разные вещи. Один - пустой блок, а один - пустой оператор.

while(...)
    statement;

Java будет интерпретировать это как:

while(...)
{
    statement;
}

что означает, что

while(...); есть while(...){;}, который тогда while(...){}

Моя точка:

Пока они производят эквивалентный байт-код (и для всех целей и целей эквивалентны), они действительно две разные вещи, которые оба приходят к одному и тому же результату с помощью пары java-правил. {} действительно не является нулевым (или пустым) оператором. Это пустой блок. В то время как за циклами должен следовать блок, поэтому пустой оператор завернут в блок, затем пустой оператор удаляется.