Ответ 1
Вопрос 1:
Почему следующий код компилируется без инструкции return?
public int a() { while(true); }
Это охватывается JLS§8.4.7:
Если у метода объявлен тип возврата (§8.4.5), тогда возникает ошибка времени компиляции, если тело метода может нормально функционировать (§14.1).
Другими словами, метод с возвращаемым типом должен возвращаться только с помощью оператора return, который обеспечивает возврат значения; методу не разрешается "опускать конец его тела". См. § 14.17 для точных правил о операторах return в теле метода.
Возможно, что метод имеет тип возврата и не содержит операторов возврата. Вот один пример:
class DizzyDean { int pitch() { throw new RuntimeException("90 mph?!"); } }
Так как компилятор знает, что цикл никогда не будет завершен (true
всегда истинно, конечно), он знает, что функция не может "нормально вернуться" (оставьте конец своего тела), и, таким образом, все в порядке, no return
.
Вопрос 2:
С другой стороны, зачем компилируется следующий код,
public int a() { while(0 == 0); }
даже если это не так.
public int a(int b) { while(b == b); }
В случае 0 == 0
компилятор знает, что цикл никогда не завершится (что 0 == 0
всегда будет true). Но он не знает, что для b == b
.
Почему бы и нет?
Компилятор понимает константные выражения (§15.28). Цитирование §15.2 - Формы выражений (потому что странно это предложение не содержится в § 15.28):
Некоторые выражения имеют значение, которое можно определить во время компиляции. Это постоянные выражения (§15.28).
В вашем примере b == b
, поскольку имеется переменная, она не является константным выражением и не указывается для определения во время компиляции. Мы можем видеть, что в этом случае оно всегда будет истинным (хотя если b
был double
, как указывал QBrute , мы легко могли бы обмануть Double.NaN
, который не ==
), но JLS указывает только, что константные выражения определены во время компиляции он не позволяет компилятору попытаться оценить не константные выражения. bayou.io поднял хороший момент, почему бы и нет: если вы начнете идти по пути определения выражений с переменными во время компиляции, где вы остановитесь? b == b
очевидно (er, для значений не NaN
), но как насчет a + b == b + a
? Или (a + b) * 2 == a * 2 + b * 2
? Рисование линии в константах имеет смысл.
Итак, поскольку он не "определяет" выражение, компилятор не знает, что цикл никогда не завершится, поэтому он думает, что метод может нормально вернуться — которое ему не разрешено делать, потому что для этого нужно использовать return
. Поэтому он жалуется на отсутствие return
.