try excepciones error catch java compiler-errors return try-catch try-catch-finally

java - excepciones - MĂșltiples declaraciones de retorno sin error del compilador



try catch throw java (8)

Esta fue una pregunta de entrevista:

public class Demo { public static void main(String[] args) { System.out.println(foo()); } static String foo() { try { return "try ..."; } catch (Exception e) { return "catch ..."; } finally { return "finally ..."; //got as result } } }

Mi pregunta es por qué no hay errores de tiempo de compilación. Cuando tengo la declaración return en mi bloque finally , es probable que regrese finally lugar de try y catch bloque. Intenté compilar este código con la opción -Xlint , da una advertencia como.

warning: [finally] finally clause cannot complete normally


(Para una respuesta corta: lea las partes en negrita y cursiva de la respuesta)

El flujo de ejecución según los documentos de Java 8. Te proporciona los detalles. Puede inferir la ejecución de declaraciones de devolución en función de lo siguiente.

Una declaración de prueba con un bloque finalmente se ejecuta ejecutando primero el bloque de prueba.

Entonces hay una opción:

• Si la ejecución del bloque try se completa normalmente, entonces se ejecuta el bloque finalmente y luego hay una opción:

- Si el bloque finalmente se completa normalmente, entonces la instrucción try se completa normalmente.

- Si el bloque finalmente se completa abruptamente por la razón S, entonces la instrucción try se completa abruptamente por la razón S.

• Si la ejecución del bloque try se completa abruptamente debido a un lanzamiento de un valor V, entonces hay una opción:

- Si el tipo de V en tiempo de ejecución es una asignación compatible con una clase de excepción capturable de cualquier cláusula catch de la declaración try, entonces se selecciona la primera cláusula catch (más a la izquierda). El valor V se asigna al parámetro de la cláusula catch seleccionada y se ejecuta el Bloque de esa cláusula catch.

Entonces hay una opción:

›Si el bloque catch se completa normalmente, se ejecuta el bloque finalmente. Entonces hay una opción:

»Si el bloque finalmente se completa normalmente, entonces la instrucción try se completa normalmente.

»Si el bloque finalmente se completa abruptamente por alguna razón, entonces la instrucción try se completa abruptamente por la misma razón.

Si el bloque catch se completa abruptamente por la razón R, entonces se ejecuta el bloque finalmente. Entonces hay una opción:

»Si el bloque finalmente se completa normalmente, entonces la instrucción try se completa abruptamente por la razón R.

» Si el bloque finalmente se completa abruptamente por la razón S, entonces la instrucción try se completa abruptamente por la razón S (y la razón R se descarta).

- Si el tipo de V en tiempo de ejecución no es compatible con una clase de excepción capturable de cualquier cláusula catch de la declaración try, entonces se ejecuta el bloque finalmente.

Entonces hay una opción:

›Si el bloque finalmente se completa normalmente, entonces la instrucción try se completa abruptamente debido a un lanzamiento del valor V.

›Si el bloque finalmente se completa abruptamente por la razón S, entonces la instrucción try se completa abruptamente por la razón S (y el lanzamiento del valor V se descarta y se olvida).

• Si la ejecución del bloque try se completa abruptamente por cualquier otra razón R, entonces el bloque finalmente se ejecuta y luego hay una opción:

- Si el bloque finalmente se completa normalmente, entonces la instrucción try se completa abruptamente por la razón R.

- Si el bloque finalmente se completa abruptamente por la razón S, entonces la instrucción try se completa abruptamente por la razón S (y la razón R se descarta).

la explicación es clara en este javaDoc


Es esencialmente lo mismo que esto:

public boolean someMethod(){ if(1 == 1){ return true; } return false; }

No dará un error de compilación, aunque dará una advertencia. El compilador solo dará un error cuando exista la posibilidad de que no se ejecute ninguna declaración de devolución.


Esto se describe en la Especificación del lenguaje Java:

§14.17

La finalización abrupta de una cláusula final puede interrumpir la transferencia de control iniciada por una declaración de return .

§14.20.2

Si la ejecución del bloque try se completa normalmente, entonces se ejecuta el bloque finally y luego hay una opción:

  • Si el bloque finally se completa normalmente, entonces la instrucción try completa normalmente.
  • Si el bloque finally se completa abruptamente por la razón S, entonces la instrucción try completa abruptamente por la razón S.

Si la ejecución del bloque try se completa abruptamente por cualquier otra razón R, entonces el bloque finally se ejecuta y luego hay una opción:

  • Si el bloque finally se completa normalmente, entonces la instrucción try completa abruptamente por la razón R.
  • Si el bloque finally se completa abruptamente por la razón S, entonces la instrucción try completa abruptamente por la razón S (y la razón R se descarta).

No da un error de compilación porque está permitido por la Especificación del lenguaje Java. Sin embargo, da un mensaje de advertencia porque incluir una declaración de return en el bloque final suele ser una mala idea.

Lo que sucede en tu ejemplo es lo siguiente. Se ejecuta la declaración de return en el bloque try . Sin embargo, el bloque finally siempre debe ejecutarse para que se ejecute después de que finalice el bloque catch . La declaración de return que ocurre allí sobrescribe el resultado de la declaración de return anterior, por lo que el método devuelve el segundo resultado.

Del mismo modo, un bloque finally no debería generar una excepción. Es por eso que la advertencia dice que el bloque finally debería completarse normalmente, es decir, sin return o lanzando una excepción.


No hay ningún error de tiempo de compilación ya que solo 1 y exactamente 1 de la declaración de return realidad devolverá el control al código de llamada.

Como se explicó en @Hoopje, el return dentro de try o catch se ejecutará primero, su respectiva declaración de retorno también se ejecutará. Pero justo antes de devolver el control al código de llamada, ejecutará el bloque finally . Ahora, este block también return algo, por lo que este retorno anula al anterior.


Pregunta brillante ... Según mi conocimiento, la declaración de devolución del bloque try and catch se transfiere finalmente a si ha agregado finalmente el bloque a su código. Así es como funciona.

Entonces, en este caso, todas las líneas de código se están ejecutando y puede intentar la depuración. Los tres bloques que probé debajo del código.

public class Main { public static void main(String[] args) { System.out.println(foo()); } static String foo() { try { throw new Exception(); } catch (Exception e) { return "catch ..."; } finally { return "finally ..."; //got as result } } }

Puede obtener la idea desde el siguiente enlace. Retornos múltiples: ¿Cuál establece el valor de retorno final?


Su código funciona bien porque solo hay una declaración de retorno en try, catch y finalmente bloquea. Se producirá un error de compilación si intenta escribir dos declaraciones de retorno dentro de una de try, catch o finalmente bloquea diciendo que hay una declaración de retorno inalcanzable.


intenta ejecutar esto:

imprimirá: 1, 2, 3 y luego lanzará una división por cero Excepción

public class Demo { public static void main(String[] args) { System.out.println(foo()); } public static String print(int a){ System.out.println(a); return String.valueOf(a/0); } static String foo() { try { return print(1); } catch (Exception e) { return print(2); } finally { return print(3); } } }