недостижимый код при попытке прекратить выполнение метода, если условие true [duplicate]

Слишком много людей помещают объекты, которые не являются потокобезопасными в одноэлементном шаблоне. Я видел примеры DataContext ( LINQ & nbsp; to SQL-файл ), выполненный в одноэлементном шаблоне, несмотря на то, что DataContext не является потокобезопасным и является чисто единичным объектом.

61
задан Peter Mortensen 28 February 2016 в 03:44
поделиться

15 ответов

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

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

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

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

EmptyStatement:
    ;

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

Это по сути означает, что вы хотите выполнить пустую инструкцию, если a == b

if(a == b);

Что вы должны сделать:

Существует две основных решения этой проблемы:

  1. Вы можете избежать проблем с пустой инструкцией с помощью форматирования кода и окружающего материала внутри if с { и }. Сделав это, ваш пустой оператор будет намного читабельнее.
    if(a == b){
      ;
    }
    
  2. Вы также можете проверить инструменты, используемые для анализа статического кода, такие как: [/g6] Findbugs Checkstyle Pmd Они могут мгновенно выделить такие проблемы, как этот.

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

81
ответ дан Marcin Szymczak 19 August 2018 в 08:01
поделиться
  • 1
    Даже самое простое решение, использующее форматирование кода, будет иметь дело с этой проблемой. Утверждение, которое должно было быть внутри if, появилось бы в том же отступе, что и if. – Patricia Shanahan 1 January 2013 в 19:54
  • 2
    Конечно, но я рекомендую использовать как форматировщик, так и статический анализ кода. – Marcin Szymczak 1 January 2013 в 19:59
  • 3
    Вы НЕ МОЖЕТЕ избежать этого, используя фигурные скобки, потому что случайная точка с запятой после закрытого паттерна и перед открытой фигурной скобкой является синтаксически действующей программой ... и, вероятно, не то, что вы хотели. Однако я согласен с тем, что код для материи может помочь избежать этой проблемы. – AgilePro 2 January 2013 в 01:09
  • 4
    должны проголосовать за эту совместную красную ошибку .... +1 (и хороший ответ) – NullPoiиteя 2 January 2013 в 10:38
  • 5
    +1 хороший ответ и большой гигантский товарный ошибка. : D – Mukul Goel 2 January 2013 в 12:15

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

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

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.

2
ответ дан AgilePro 19 August 2018 в 08:01
поделиться
  • 1
    Приятно, если иначе, если, например, интересно, никто не упоминал об этом здесь. +1 – Mordechai 4 July 2017 в 04:40

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

if(a==b) {
    ;
}
7
ответ дан André Stannek 19 August 2018 в 08:01
поделиться
  • 1
    +1, наиболее четкое и краткое объяснение того, почему это так, не предполагая знания. – Sorpigal 2 January 2013 в 03:17

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

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.

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

-2
ответ дан azro 19 August 2018 в 08:01
поделиться
  • 1
    if(row != 0) method (grid[row][col], grid[row-1][col]); будет иметь тот же эффект без использования пустых if операторов. – intcreator 27 June 2017 в 16:34

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

Блоки являются состояниями

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

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

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

IfThenStatement:
    if ( Expression ) Statement

IfThenElseStatement:
    if ( Expression ) StatementNoShortIf else Statement

IfThenElseStatementNoShortIf:
    if ( Expression ) StatementNoShortIf else StatementNoShortIf

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

Но с чем это связано? ?

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

Таким образом, if(Expression)EmptyStatement works.

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

Довольно просто: java дает ошибку, если находит недопустимый синтаксис. Но if(Expression)EmptyStatement - вполне допустимый синтаксис. Вместо этого javac выдает предупреждение при запуске с соответствующими параметрами. Полный список предупреждений, которые могут быть отключены для , для этой цели содержит имя-предупреждение empty. Таким образом, компиляция с -Xlint:all или -Xlint:empty будет генерировать предупреждение об этом.

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

Что это даже используется для?

Честно говоря, в нем мало пользы с минималистской точки зрения. Обычно есть способ добиться успеха без команды «ничего не делать». Скорее, речь идет о личных предпочтениях, предпочитаете ли вы использовать

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

или

if( a() ) b();

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

1
ответ дан Community 19 August 2018 в 08:01
поделиться

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

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

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

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

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

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

6
ответ дан Edwin Buck 19 August 2018 в 08:01
поделиться
if(a==b)
    println("a equals b");

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

1
ответ дан Matt Clark 19 August 2018 в 08:01
поделиться

Точка с запятой в конце, если (a == b); просто закончить оператор в одной строке, что означает игнорировать результат условия и продолжить выполнение из следующей строки. Этот код полезен, с другой стороны, когда-то вводит ошибку в программу, например, случай 1. a = 5; b = 3; если (a == b); prinf («a и b равны»); случай 2. a = 5; b = 5; если (a == b); prinf («a и b равны»); будет печатать тот же результат на экране ...

0
ответ дан Narayan Bhandari 19 August 2018 в 08:01
поделиться
  • 1
    & quot; Этот код полезен & quot; & lt; - Как было бы полезно игнорировать результат условия? – vegemite4me 2 January 2013 в 12:37
  • 2
    да, в if-elseif иерархии, если мы должны игнорировать результат определенных условий, это может быть использовано. например – Narayan Bhandari 18 September 2014 в 09:19

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

Java->Compiler->Errors/Warnings [/g0]

10
ответ дан nullptr 19 August 2018 в 08:01
поделиться

Я могу думать о сценарии, где требуется пустой оператор (не для условия 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
0
ответ дан Parvez 19 August 2018 в 08:01
поделиться

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

 while(do something);

или

 for(init; do something; something else);

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

5
ответ дан Peter Lawrey 19 August 2018 в 08:01
поделиться

Просто FYI о юзабилити и , какую разницу он делает или может сделать, если существует такая инструкция

. Рассмотрим фрагмент кода, такой как следующий.

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

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

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

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

19
ответ дан Peter Mortensen 19 August 2018 в 08:01
поделиться
  • 1
    if(a!=b) кажется более читаемым – Marcin Szymczak 1 January 2013 в 21:56
  • 2
    @DeMoon конечно. Я сказал, что это не хорошо :) – gefei 1 January 2013 в 22:03
  • 3
    +1, но пример использования не нужен. Как вы можете показать, его можно использовать, но это далеко не лучший способ организовать этот код. Это уродливо, но нет причин для особого случая, чтобы отклонить - по крайней мере, от POV компилятора. От шлема ... – jmoreno 2 January 2013 в 02:58
  • 4
    Подобный код может фактически предотвратить ошибки в логике путем учета всех случаев. «Если истина ничего не делает, иначе ...» может быть более читаемым, поскольку вы не путаетесь ошибками отрицания и «отсутствующим случаем». Большинство компиляторов в эти дни знают об этой конструкции и инвертируют для вас в любом случае для улучшения скорости. например Язык Меркурия обеспечивает это! – tudor 2 January 2013 в 06:33
  • 5
    @tudor, я бы сказал, даже для этого варианта использования, было бы лучше сделать if (a==b) { // do nothing } else { doSomething(); }, так как более очевидно, что no-op предназначен специально, а не опечатка. – yshavit 5 January 2013 в 22:36
  • 6
    @yshavit Это правда. Комментарии помогают сделать вещи более ясными времени, но это отличается от этой конструкции. Кроме того, нет функциональной разницы между if (a == b); // ничего не делаем и если (a == b) {/ * ничего не делать * /} Оба будут оптимизированы, удалив комментарий и пустой регистр и инвертируя условное. – tudor 6 January 2013 в 02:58

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

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

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

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

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

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

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

27
ответ дан Tim Medora 19 August 2018 в 08:01
поделиться
  • 1
    @gefei - это стиль horrible , насколько я могу судить. – Tim Medora 1 January 2013 в 19:28
  • 2
    Вы можете сделать то же самое с помощью только a() && b();. – Gumbo 1 January 2013 в 19:30
  • 3
    Нет, это просто заставляет будущего читателя смущаться относительно того, является ли это опечаткой. Почему бы просто не быть предельно ясным и только немного более многословным? if(!a()) b(); – yshavit 1 January 2013 в 19:34
  • 4
    @Gumbo - Ты уверен, что работает? Моя Java ржавая, но я не мог получить () & amp; & amp; b () для работы: ideone.com/beVwPe – Tim Medora 2 January 2013 в 17:41
  • 5
    @TimMedora. Моя ошибка, я что-то перепутал (т. Е. Assignment и AssignmentExpression ) и на самом деле не протестировал его (возможно, потому, что другие языки допускают такие заявления). A Statement допускает только первое Assignment , в то время как указанное выражение a() && b() будет AssignmentExpression . – Gumbo 2 January 2013 в 18:21

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

4
ответ дан yshavit 19 August 2018 в 08:01
поделиться
19
ответ дан Peter Mortensen 30 October 2018 в 20:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: