Clarificación de try-catch-finally-return

Al leer todas las preguntas ya formuladas en este foro relacionadas con el tema anterior (ver título), entiendo perfectamente que finally siempre se llama. (excepto desde System.exit e infinite loops). Sin embargo, me gustaría saber si se llama a una return en un bloque catch y luego se llama otra return desde el bloque finally.

Por ejemplo:

 public static void main(String[]args) { int a = new TestClass().absorbeTheValue(); } int absorbeTheValue() { try { int a = 10/0; if (a > 0) return 4; } catch(Exception e) { return 45; } finally { return 34; } } 

Entonces aquí la salida (cuando se llama el método) va a ser 34 en cualquier caso. Significa que finalmente siempre se ejecuta. Aunque creo que los otros “retornos” no se ejecutan en absoluto. En muchas publicaciones encontré el hecho de que finalmente escribo el contenido sobre lo que ya había sido escrito por el retorno de la cláusula de captura. Según entiendo, tan pronto como el valor de retorno en la cláusula de captura esté a punto de evaluarse, el flujo de control pasará a la cláusula finally que tiene a su vez otra devolución, esta vez la devolución se evaluará sin pasar el control a la cláusula de captura . De esta forma, la única return llamada en tiempo de ejecución será la devolución final. ¿Estás de acuerdo con eso?

Una return en finally no devuelve el control al progtwig pero devuelve el valor y finaliza el método. ¿Podemos decir eso?

Si se alcanza el return en el bloque try , transfiere el control al bloque finally , y la función eventualmente retorna normalmente (no a throw).

Si se produce una excepción, pero luego el código llega a un return desde el bloque catch , el control se transfiere al bloque finally y la función eventualmente retorna normalmente (no un throw).

En su ejemplo, tiene un return al final, y así independientemente de lo que suceda, la función devolverá 34 , porque finally tiene la palabra final (si se quiere).

Aunque no está cubierto en su ejemplo, esto sería cierto incluso si no tenía la catch y si se arrojó una excepción en el bloque try y no se atrapó. Al hacer un return desde el bloque finally , suprime la excepción por completo. Considerar:

 public class FinallyReturn { public static final void main(String[] args) { System.out.println(foo(args)); } private static int foo(String[] args) { try { int n = Integer.parseInt(args[0]); return n; } finally { return 42; } } } 

Si ejecuta eso sin proporcionar ningún argumento:

  $ java FinallyReturn 

… el código en foo arroja una ArrayIndexOutOfBoundsException . Pero debido a que el bloque finally realiza una return , esa excepción se suprime.

Esta es una de las razones por las que es mejor evitar el uso de return en finally .

Aquí hay un código que muestra cómo funciona.

 class Test { public static void main(String args[]) { System.out.println(Test.test()); } public static String test() { try { System.out.println("try"); throw new Exception(); } catch(Exception e) { System.out.println("catch"); return "return"; } finally { System.out.println("finally"); return "return in finally"; } } } 

El resultado es:

 try catch finally return in finally