Pregunta 1:
¿Por qué se compila el siguiente código sin tener una declaración de retorno?
public int a()
{
while(true);
}
Esto está cubierto por JLS§8.4.7 :
Si se declara que un método tiene un tipo de retorno (§8.4.5), se produce un error en tiempo de compilación si el cuerpo del método puede completarse normalmente (§14.1).
En otras palabras, un método con un tipo de retorno debe regresar solo mediante el uso de una declaración de retorno que proporcione un valor de retorno; el método no puede "dejar el extremo de su cuerpo". Vea §14.17 para las reglas precisas sobre las declaraciones de retorno en un cuerpo de método.
Es posible que un método tenga un tipo de retorno y, sin embargo, no contenga declaraciones de retorno. Aquí hay un ejemplo:
class DizzyDean {
int pitch() { throw new RuntimeException("90 mph?!"); }
}
Como el compilador sabe que el ciclo nunca terminará ( true
siempre es cierto, por supuesto), sabe que la función no puede "regresar normalmente" (dejar el extremo de su cuerpo), y por lo tanto está bien que no haya return
.
Pregunta 2:
Por otro lado, ¿por qué se compila el siguiente código?
public int a()
{
while(0 == 0);
}
aunque lo siguiente no.
public int a(int b)
{
while(b == b);
}
En el 0 == 0
caso, el compilador sabe que el ciclo nunca terminará (eso 0 == 0
siempre será cierto). Pero no lo sabe por b == b
.
Por qué no?
El compilador comprende expresiones constantes (§15.28) . Citando §15.2 - Formas de expresiones (porque curiosamente esta oración no está en §15.28) :
Algunas expresiones tienen un valor que se puede determinar en tiempo de compilación. Estas son expresiones constantes (§15.28).
En su b == b
ejemplo, debido a que hay una variable involucrada, no es una expresión constante y no se especifica que se determine en el momento de la compilación. Podemos ver que siempre será cierto en este caso (aunque si b
fuera un double
, como señaló QBrute , podríamos engañarnos fácilmente Double.NaN
, lo que no==
es en sí mismo ), pero el JLS solo especifica que las expresiones constantes se determinan en el momento de la compilación , no permite que el compilador intente evaluar expresiones no constantes. bayou.io planteó un buen punto para por qué no: si comienza a tratar de determinar expresiones que involucran variables en el momento de la compilación, ¿dónde se detiene? b == b
es obvio (er, para noNaN
valores), pero ¿qué pasa a + b == b + a
? O (a + b) * 2 == a * 2 + b * 2
? Dibujar la línea en las constantes tiene sentido.
Por lo tanto, dado que no "determina" la expresión, el compilador no sabe que el ciclo nunca terminará, por lo que cree que el método puede regresar normalmente, lo que no está permitido, porque es obligatorio return
. Entonces se queja de la falta de a return
.