Los detalles del caso de Java para esto (que probablemente son muy similares al caso de C #) tienen que ver con la forma en que el compilador de Java determina si un método puede regresar.
Específicamente, las reglas son que un método con un tipo de retorno no debe poder completarse normalmente y en su lugar siempre debe completarse abruptamente (abruptamente aquí indicando mediante una declaración de retorno o una excepción) según JLS 8.4.7 .
Si se declara que un método tiene un tipo de retorno, se produce un error en tiempo de compilación si el cuerpo del método puede completarse normalmente. En otras palabras, un método con un tipo de retorno debe devolver solo mediante el uso de una declaración de retorno que proporciona un valor de retorno; no está permitido "dejar el extremo de su cuerpo" .
El compilador busca ver si la terminación normal es posible en función de las reglas definidas en JLS 14.21 Declaraciones inalcanzables, ya que también define las reglas para la finalización normal.
En particular, las reglas para las declaraciones inalcanzables hacen un caso especial solo para los bucles que tienen una trueexpresión constante definida :
Una instrucción while puede completarse normalmente si al menos uno de los siguientes es verdadero:
Entonces, si la whiledeclaración puede completarse normalmente , entonces es necesaria una declaración de retorno a continuación, ya que el código se considera accesible, y cualquier whileciclo sin una declaración de ruptura alcanzable o trueexpresión constante se considera capaz de completarse normalmente.
Estas reglas significan que su whiledeclaración con una verdadera expresión constante y sin una breakestá nunca se consideró a completar normalmente , por lo que cualquier código de abajo se nunca se consideró para ser alcanzable . El final del método está debajo del ciclo, y dado que todo lo que está debajo del ciclo es inalcanzable, también lo es el final del método y, por lo tanto, el método no puede completarse normalmente (que es lo que busca el cumplidor).
if las declaraciones, por otro lado, no tienen la exención especial con respecto a las expresiones constantes que se otorgan a los bucles.
Comparar:
// I have a compiler error!
public boolean testReturn()
{
final boolean condition = true;
if (condition) return true;
}
Con:
// I compile just fine!
public boolean testReturn()
{
final boolean condition = true;
while (condition)
{
return true;
}
}
La razón de la distinción es bastante interesante, y se debe al deseo de permitir marcas de compilación condicional que no causen errores de compilación (del JLS):
Uno podría esperar que la declaración if se maneje de la siguiente manera:
Una instrucción if-then puede completarse normalmente si al menos uno de los siguientes es verdadero:
La declaración then es accesible si la declaración if-then es accesible y la expresión de condición no es una expresión constante cuyo valor es falso.
Una declaración if-then-else puede completarse normalmente si la declaración then puede completarse normalmente o la declaración else puede completarse normalmente.
La declaración then es accesible si la declaración if-then-else es accesible y la expresión de condición no es una expresión constante cuyo valor es falso.
La declaración else es accesible si la declaración if-then-else es accesible y la expresión de condición no es una expresión constante cuyo valor es verdadero.
Este enfoque sería coherente con el tratamiento de otras estructuras de control. Sin embargo, para permitir que la declaración if se use convenientemente para propósitos de "compilación condicional", las reglas reales difieren.
Como ejemplo, la siguiente declaración da como resultado un error en tiempo de compilación:
while (false) { x=3; }porque la declaración x=3;no es accesible; pero el caso superficialmente similar:
if (false) { x=3; }no produce un error en tiempo de compilación. Un compilador optimizador puede darse cuenta de que la declaración x=3;nunca se ejecutará y puede optar por omitir el código para esa declaración del archivo de clase generado, pero la declaración x=3;no se considera "inalcanzable" en el sentido técnico especificado aquí.
La razón de este tratamiento diferente es permitir que los programadores definan "variables de marca" como:
static final boolean DEBUG = false; y luego escribe código como:
if (DEBUG) { x=3; } La idea es que debería ser posible cambiar el valor de DEBUG de falso a verdadero o de verdadero a falso y luego compilar el código correctamente sin otros cambios en el texto del programa.
¿Por qué la declaración de interrupción condicional da como resultado un error del compilador?
Como se cita en las reglas de accesibilidad de bucle, un bucle while también puede completarse normalmente si contiene una declaración de interrupción alcanzable. Dado que las normas para la accesibilidad de una ifde declaración a continuación cláusula de no tener la condición de la ifen consideración en absoluto, tal condicional ifde la declaración a continuación, la cláusula se considera siempre localizable.
Si breakse puede acceder a él, el código después del ciclo también se considera accesible nuevamente. Dado que no hay un código accesible que dé como resultado una terminación abrupta después del ciclo, el método se considera capaz de completarse normalmente, por lo que el compilador lo marca como un error.