Este es un ejemplo artificial. Tengo un método no nulo y arroja una excepción. ¿Por qué no tengo que devolver un valor después? Después de todo, el método no es nulo.
public static Toast makeText(Context context, CharSequence text, int duration) { throw new RuntimeException("Stub!"); //Must return something from here but there is not, Why? }Lanzar una excepción interrumpe el flujo de control, saliendo del método inmediatamente. Cuando se lanza una excepción, no se necesita ningún valor de retorno porque el código que llamó al método no se completa normalmente. Por ejemplo, en el siguiente código, no es necesario que foo devuelva un número, porque int x = foo(); no tiene éxito, en su lugar propaga la excepción:
int foo() { throw new RuntimeException(); } void bar() { int x = foo(); // This line will not be reached System.out.println(x); } Dado que el código después de int x = foo(); no se ejecutará de todos modos, no es necesario que x reciba un valor de retorno de foo y, por lo tanto, foo no necesita proporcionar un valor de retorno.
De hecho, un método no puede devolver un valor y también lanzar una excepción, ya que devolver un valor significaría que el método se completa normalmente.
No existe un requisito real para que un método que devuelve un valor contenga una declaración de devolución. Quizás sorprendentemente, este código es legal:
int noReturn() { while (true) {} }La gran clave de la especificación del lenguaje es JLS 8.4.7 , que dice:
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).
La "finalización normal" se describe en JLS 14.1 :
Cada declaración tiene un modo normal de ejecución en el que se llevan a cabo ciertos pasos computacionales. Las siguientes secciones describen el modo normal de ejecución para cada tipo de instrucción.
Si todos los pasos se llevan a cabo como se describe, sin indicación de finalización abrupta, se dice que la declaración se completa normalmente. Sin embargo, ciertos eventos pueden impedir que una declaración se complete normalmente:
- Las declaraciones break, yield, continue y return (§14.15, §14.21, §14.16, §14.17) provocan una transferencia de control que puede impedir la finalización normal de expresiones, declaraciones y bloques que las contienen.
- La evaluación de ciertas expresiones puede arrojar excepciones de la máquina virtual de Java (§15.6). Una instrucción throw explícita (§14.18) también da como resultado una excepción. Una excepción provoca una transferencia de control que puede impedir la finalización normal de las sentencias.
Entonces: el requisito es que el método no debe completarse normalmente; y tanto return como throw son formas de hacer que el método se complete de manera anormal.
Tenga en cuenta que esto no dice que el método deba completarse de manera anormal en su lugar: volviendo al ejemplo de ciclo while al principio, que no se completa normalmente o de manera anormal: porque la condición del ciclo es un verdadero verdadero y no contiene un retorno , throw or break, o una declaración que podría lanzar una excepción, ese ciclo nunca se completa, lo cual también está bien (al menos desde la perspectiva del lenguaje).