java - Clarificación de try-catch-finally-return
try finally java (2)
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
Esta pregunta ya tiene una respuesta aquí:
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 programa 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
.