Точка с запятой в конце инструкции if

сегодня, после получаса поиска ошибки, я обнаружил, что можно поставить точку с запятой после оператора if вместо кода, например:

if(a == b);
// Do stuff

что в основном означает, что материал будет выполнен независимо от того, равен ли a b или нет, и оператор if не имеет никакого смысла. Почему Java не дает мне ошибку? Есть ли ситуации, в которых это было бы полезно?

16 ответов


почему это происходит?

Спецификация Языка Java говорит, что:

Пустое Заявление

пустое утверждение ничего не делает.

EmptyStatement:
    ;

выполнение пустой инструкции всегда завершается нормально

это по существу означает, что вы хотите выполнить пустой оператор, если a==b

if(a == b);

что нужно делать:

есть два основные решения этой проблемы:

  1. вы можете избежать проблем с пустым оператором с помощью форматирования кода и окружающие вещи внутри if С { и }. Сделав это Ваше пустое утверждение будет гораздо более читаемым.

    if(a == b){
      ;
    }
    
  2. вы также можете увидеть инструменты, используемые для статического анализа кода, такие как:

    они могут мгновенно выделить такие проблемы, как эта.

Я бы рекомендовал объединить оба решения.


есть ли ситуация, в которой это было бы полезно?

полезное? Как в "делает ваш код чище, яснее, быстрее, более ремонтопригодным"? Нисколько. Это, скорее всего,плохой, запутанный код.

но это не обязательно доброкачественную. Такое утверждение может выполнять действия и / или изменять состояние из-за методов, которые вызывают побочные эффекты, и необязательно оценивать эти методы из-за короткое замыкание операторы.

if( a() && b() );

здесь a() или b() может что-то сделать, и b() будет выполняться только если a() - Это правда.

как почему, я думаю, что ответ просто в том, что было бы хуже отклоняться от определенного, ожидаемого поведения (например, такие утверждения, как while(reader.read());), чем альтернатива разработчиков, пишущих плохой код.

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


возможный вариант использования:

if (a==b);
else {
  // Do something
}

не есть хорошо, но возможно.

тем не менее, я думаю, что спецификация Java должна запретить пустое if.


Если вы используете Eclipse, вы можете предупредить вас об этих заявлениях:

Java->Compiler->Errors/Warnings


если вы используете if оператор, первый оператор после if будет выполнено, если условие истинно. Если у вас есть блок после if (с фигурными скобками), это считается для всего блока. Если блока нет, он имеет значение только для одного оператора. Одна точка с запятой-это пустой оператор. Вы также можете написать код от вас пример такой:

if(a==b) {
    ;
}

Это старый пережиток дней, когда было больше синтаксического сахара, чтобы отличать выражения от заявления.

В основном запятая использовалась как разделитель элементов списка, поэтому точка с запятой использовалась как разделитель "список операторов". Недостатком является обработка нулевых элементов в списках и нулевых операторов в блоках.

В списке элементов Java использует явное ключевое слово null, но "нулевой оператор" - это просто пустая строка. Позволять существование пустой строки является пережитком традиции, унаследованной от C.

почему это? Особенно с if оператор, когда вы знаете, что никакие операторы не выполняются: потому что некоторые операторы if имеют побочные эффекты:

 int c;
 if ((c = in.read()) != -1);

Да, это не лучший пример, но в основном он говорит прочитать байт из потока и ничего не делать. Может быть полезно в некоторых случаях, но даже если этот пример не самый лучший, он иллюстрирует замысел. Мы хотим почувствовать побочные эффекты выражения без случайного выполнения каких-либо заявлений.


Я не могу придумать случая, когда это полезно. Это может быть полезно для циклов, таких как

 while(do something);

или

 for(init; do something; something else);

Если вы регулярно используете форматирование кода в IDE, такие ошибки становятся очевидными. Некоторые IDEs выделяют это как вероятную ошибку.


Я согласен с вами, что для человека нет никакой полезной цели. Я подозреваю, что это потому, что это упрощает определение языка; это означает, что вещь, которая приходит после if Это то же самое, что и вещь, которая приходит после while, например.


почему? Это потому, что это проще для авторов компиляторов. Вам не нужно делать особый случай, чтобы проверить наличие точек с запятой после if(cond) и имеет дополнительное использование разрешения

if (cond && maybeFunc())
    ;// Code here I want to ignore

хотя на самом деле это ужасная идея, чтобы позволить это. Просто проще разрешить, а затем добавить случай, чтобы проверить это.


Java позволяет пустому блоку любое место, где разрешен блок оператора. Я уверен, что это общее правило для всех блоков упрощает компилятор.

Я согласен, что это в первую очередь причину ошибки, невероятно трудно найти. Я всегда использую фигурные скобки вокруг блоков, даже когда есть один оператор, но Java позволяет сделать блок с фигурными скобками в любой момент, поэтому использование фигурных скобок не может спасти вас от этой судьбы. Например, я однажды потратил 4 часа, пытаясь найти что-то вроде этого:--3-->

while (condition);
{
    statement;
    statement;
}

точка с запятой в конце первой строки была опечаткой, случайно сделав блок оператора для цикла while пустым. Поскольку синтаксис действителен, программа скомпилирована и работает нормально, просто не так, как я хотел. Это было действительно трудно найти.

Я могу придумать ситуации, где это очень приятно что вам разрешено иметь пустые блоки, и это что-то вроде это:

if (condition1) {
    do_action_1();
}
else if (condition2) {
    //nothing really to do in this case
}
else if (condition3) {
    do_action2();
}
else {
    do_action3();
}

в приведенном выше примере вы хотите иметь возможность отделять различные условия. Помните, что эти условия могут перекрываться,поэтому не всегда возможно изменить порядок. Если одно из условий действительно ничего не нужно делать, то приятно, что Java позволяет иметь пустой блок. В противном случае язык будет нуждаться в какой-то форме метода "noop" для использования, когда вы действительно ничего не хотите делать.

Я лично предпочел бы явное утверждение "noop" - но это не то, как определяется Java.


просто FYI о удобстве использования и какое это имеет значение или может иметь, если есть такое утверждение

рассмотрим фрагмент кода, как показано ниже.

int a = 10;
if ((a = 50) == 50);

System.out.println("Value of a = " + a);

ясно, что в данном случае if оператор изменяет выходные данные. Таким образом, такое утверждение может иметь значение.

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


if(a==b)
    println("a equals b");

вы можете использовать оператор IF без {} если есть только одна строка для выполнения, поэтому с помощью if(a==b); вы говорите, если они равны, выполнить и пустое заявление... Поэтому он ничего не будет делать, а затем вернется к вашему обычному циклу, вне блока IF.


несколько определений из jls объясняют это (Глава 14):

блоки отчетность

как заявил здесь, a Block - это StatementWithoutTrailingSubstatement, который в свою очередь является StatementNoShortIf, который является Statement. Таким образом, где бы любой из них требуется, мы можем вставить тег Block.

предложение if

хотя это так же верно для for и while-петли, я использую if-заявления. Эти правила почти такие же. Этот синтаксическое описание if-statements можно найти здесь.

IfThenStatement:
    if ( Expression ) Statement

IfThenElseStatement:
    if ( Expression ) StatementNoShortIf else Statement

IfThenElseStatementNoShortIf:
    if ( Expression ) StatementNoShortIf else StatementNoShortIf

так что мы можем использовать наш блок здесь.

но почему он работает с ; ?

; определяется как EmptyStatement (ссылке), который также является StatementNoShortIf. Поэтому в условных фрагментах кода, например if-statement и петли, мы можем заменить Block С EmptyStatement, если a StatementNoShortIf или это.

if(Expression)EmptyStatement завод.

почему это не дает ошибку?

довольно просто: java дает ошибку, если находит недопустимый синтаксис. Но!--20--> - это вполне допустимый синтаксис. Вместо javac выдает предупреждение при запуске с соответствующими параметрами. The полный список предупреждений, которые могут быть dis-/enabled перечисляет предупреждение-имя empty для этой цели. Итак, компиляция с -Xlint:all или -Xlint:empty выдаст предупреждение об этом.

ваша IDE должна иметь возможность включения такого рода предупреждение. Для eclipse см. ответ@nullptr. В IntelliJ, вы можете нажать Ctrl + Shift + A, enter empty body в поле поиска и включить предупреждение (отмечено на изображении)

IntelliJ enable empty-body warning

для чего это вообще используется?

честно говоря, в этом нет большой пользы с минималистической точки зрения. Обычно есть способ сделать что-то без команды "ничего не делать". Это скорее вопрос личных предпочтений, предпочитаете ли вы использовать

if( a() && b() );

или

if( a() ) b();

и то же самое относится к другим случаям, в которых это. Важным моментом для рассмотрения этой темы является читаемость кода. Бывают случаи, когда код становится более читаемым с помощью no-op. С другой стороны, есть случаи, когда код становится намного сложнее понять с помощью EmptyStatement - приведенный выше пример будет считаться более поздним ММО.


точка с запятой в конце,
if (a==b); просто завершите оператор в одной строке, что означает игнорировать результат условия и продолжить выполнение из следующей строки
Этот код полезен, с другой стороны когда-нибудь ввести ошибку в программе, например,

корпус 1.

a = 5;
b = 3;
если (a == b);
prinf ("a и b равны");

корпус 2.

a = 5;
b = 5;
Если(а == b);
prinf ("a и b равны");
будет печатать тот же вывод на экран...


Я могу придумать сценарий, в котором требуется пустой оператор (не для if состоянии, но для while петли).

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

    System.out.println("Enter Y to proceed. Waiting...");
    System.out.println("");

    while(!(new Scanner(System.in).next().equalsIgnoreCase("Y")));

    System.out.println("Proceeding...");
    // do the work here

во время работы над назначением программирования для класса, где я работаю с сеткой N на N рисунков и сравниваю характеристики случайного рисунка с теми, что выше, ниже, слева и справа, я нашел хорошее использование этого, чтобы предотвратить вложенные операторы и потенциальные граничные исключения. Моя цель состояла в том, чтобы свести к минимуму код и не вложить if-операторы.

if (row == 0); 
else (method (grid[row][col], grid[row-1][col]));
if (row == N-1);
else (method (grid[row][col], grid[row+1][col]));
if (col == 0);
else (method (grid[row][col], grid[row][col-1]));
if (col == N-1);<br>
else (method (grid[row][col], grid[row][col+1]));

здесь method(Doodad a, Doodad b) выполняет некоторую операцию между a и b.

кроме того, вы можете использовать исключение обработка, чтобы избежать этого синтаксиса, но он работает и хорошо работает для моего приложения.