Специфика случая 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 такого условного оператора всегда считается достижимым.ifif
Если значение breakдостижимо, то код после цикла снова считается также достижимым. Поскольку нет доступного кода, который приводит к внезапному завершению после цикла, считается, что метод может нормально завершиться, и поэтому компилятор помечает его как ошибку.