Почему компилятор Java не создает ошибку недостижимого оператора для недостижимого оператора then?


если я попытаюсь скомпилировать

for(;;)
{

}
System.out.println("End");

компилятор Java выдает ошибку, говоря:Unreachable statement. Но если я добавлю еще один "недоступен"(по-моему) break заявление и сделают это:

for(;;)
{
    if(false) break;
}
System.out.println("End");

он компилирует. Почему это не приводит к ошибке? Java пытается сказать, что две ошибки do сделать правильно?

5 58

5 ответов:

поведение определяется в описание JLS недостижимых операторов:

then-оператор является достижимой эквивалентностью, если-то заявление можно.

поэтому компилятор определяет, что оператор then - (break;) достижимо, независимо от условия в if.

и чуть дальше, выделено мной:

базовый for оператор может обычно завершать эквивалентность, по крайней мере верно одно из следующих утверждений:

  • оператор for можно, есть выражение условия, и выражение условия не является константным выражением (§15.28) со значением true.
  • есть достижимое break оператор, который выходит из оператора for.

таким образом, for может завершиться нормально, потому что оператор then-содержит break. Как вы заметили, это не сработает, если вы заменили break С return.


обоснование объясняется в конце раздела. По существу, if имеет специальное обращение, чтобы позволить конструкции, такие как:

if(DEBUG) { ... }

где DEBUG может быть константой времени компиляции.

Как поясняется в мой ответ на подобный вопрос конкретные конструкцию if(compile-time-false) освобождается от правил недостижимости как явный бэкдор. В этом случае, компилятор обрабатывает код break как можно добраться из-за этого.

С JLS

оператор if-then может завершаться нормально, если хотя бы один из верно следующее:

> оператор if-then доступен, а выражение условия-нет постоянное выражение, значение которого равно true.

> то-заявление может завершить нормально.

Так if(false) разрешено.

эта способность "условно компилировать" оказывает существенное влияние на, и отношение к двоичной совместимости. Если набор классов что использовать такой" флаг " переменной компилируются и условный код опущено, это не достаточно позже, чтобы распространять только новую версию класс или интерфейс, содержащий определение флага. Один поэтому изменение значения флага не совместимо с двоичным кодом с уже существующими двоичными файлами . (Есть и другие причины такие несовместимости, например, такие использование констант в случае метки в операторах switch;)

по сути, недостижимый код определяется путем анализа программы статическибез на самом деле выполняется код. При этом условие будет проверяться по адресу runtime. Итак, когда этот анализ происходит, он фактически не смотрит на условие, а просто проверяет это break; доступен(достижим) через if.

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

итак, ясно, что все недостижимые операторы не могут быть обнаружены, но почему бы не попробовать оценить условия? Представьте теперь, что используемое условие не просто false но что-то вроде ~x == x. Например, все эти заявления будут печатать true для каждого int x (источник).

    System.out.println((x + x & 1) == 0);
    System.out.println((x + -x & 1) == 0);
    System.out.println((-x & 1) == (x & 1));
    System.out.println(((-x ^ x) & 1) == 0);
    System.out.println((x * 0x80 & 0x56) == 0);
    System.out.println((x << 1 ^ 0x1765) != 0);

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

остался только один вопрос: где остановить разрешение условий? Причин для этого, похоже, нет имеют математическое обоснование и основаны на сценарии использования. Обоснование для вашего конкретного случая определяется JLS-14.21