Специфика случая Java для этого (которая, вероятно, очень похожа на случай C #) связана с тем, как компилятор Java определяет, может ли метод вернуться.
В частности, правила таковы, что метод с возвращаемым типом не должен иметь возможность нормально завершаться и вместо этого должен всегда завершаться преждевременно (здесь резко с помощью оператора возврата или исключения) согласно JLS 8.4.7 .
Если объявлен метод с возвращаемым типом, то возникает ошибка времени компиляции, если тело метода может завершиться нормально. Другими словами, метод с возвращаемым типом должен возвращать только с помощью оператора return, который обеспечивает возвращаемое значение; не допускается «опускание конца его тела» .
Компилятор проверяет , возможно ли нормальное завершение, основываясь на правилах, определенных в JLS 14.21 Недоступные утверждения, так как он также определяет правила для нормального завершения.
Примечательно, что правила для недостижимых операторов делают особый случай только для циклов, которые имеют определенное true
константное выражение:
Оператор while может обычно завершаться, если хотя бы одно из следующих условий верно:
Оператор while достижим, и выражение условия не является константным выражением (§15.28) со значением true.
Существует оператор достижимого прерывания, который выходит из оператора while.
Таким образом, если while
оператор может завершиться нормально , тогда оператор возврата ниже необходим, поскольку код считается достижимым, и любой while
цикл без оператора достижимости или константы с true
выражением считается способным завершиться нормально.
Эти правила означают , что ваше while
заявление с постоянным истинным выражением и без break
никогда не считало , чтобы завершить нормально , и поэтому любой код под ним не разу не считаются достижимыми . Конец метода находится ниже цикла, и поскольку все, что находится ниже цикла, недоступно, так же как и конец метода, и, таким образом, метод не может завершиться нормально (именно это ищет компилятор).
if
операторы, с другой стороны, не имеют специального исключения в отношении константных выражений, которые предоставляются циклам.
Для сравнения:
// I have a compiler error!
public boolean testReturn()
{
final boolean condition = true;
if (condition) return true;
}
С участием:
// I compile just fine!
public boolean testReturn()
{
final boolean condition = true;
while (condition)
{
return true;
}
}
Причина различия довольно интересна и связана с желанием разрешить флаги условной компиляции, которые не вызывают ошибок компиляции (из JLS):
Можно ожидать, что оператор if будет обработан следующим образом:
Оператор if-then может обычно завершаться, если хотя бы одно из следующих условий верно:
Оператор if-then достижим, и выражение условия не является константным выражением, значение которого равно true.
Оператор then может завершиться нормально.
Оператор then достижим, если оператор if-then достижим, и выражение условия не является константным выражением, значение которого равно false.
Оператор if-then-else может завершиться нормально, если оператор then может завершиться нормально или оператор else может завершиться нормально.
Оператор then достижим, если оператор if-then-else достижим, а выражение условия не является константным выражением, значение которого равно false.
Оператор else доступен, если оператор if-then-else достижим, а выражение условия не является константным выражением, значение которого равно true.
Такой подход согласуется с трактовкой других контрольных структур. Однако для того, чтобы оператор if мог удобно использоваться для целей «условной компиляции», действительные правила различаются.
Например, следующий оператор приводит к ошибке во время компиляции:
while (false) { x=3; }
потому что утверждение x=3;
недостижимо; но внешне похожий случай:
if (false) { x=3; }
не приводит к ошибке времени компиляции. Оптимизирующий компилятор может понять, что оператор x=3;
никогда не будет выполнен, и может решить пропустить код для этого оператора из сгенерированного файла класса, но оператор x=3;
не считается «недоступным» в техническом смысле, указанном здесь.
Обоснование этого отличающегося подхода состоит в том, чтобы позволить программистам определять «переменные-флажки», такие как:
static final boolean DEBUG = false;
а затем написать код, такой как:
if (DEBUG) { x=3; }
Идея состоит в том, что должна быть возможность изменить значение DEBUG с false на true или с true на false, а затем правильно скомпилировать код без каких-либо других изменений в тексте программы.
Почему оператор условного прерывания приводит к ошибке компилятора?
Как указано в правилах достижимости цикла, цикл while может также завершиться нормально, если он содержит достижимый оператор break. Поскольку правила достижимости предложения thenif
оператора вообще не принимают во внимание условие условия , предложение then такого условного оператора всегда считается достижимым.if
if
Если значение break
достижимо, то код после цикла снова считается также достижимым. Поскольку нет доступного кода, который приводит к внезапному завершению после цикла, считается, что метод может нормально завершиться, и поэтому компилятор помечает его как ошибку.