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