statement - ¿Un bloque finalmente se ejecuta siempre en Java?
sintaxis try catch (30)
La respuesta es simple, sí.
ENTRADA:
try{
int divideByZeroException = 5 / 0;
} catch (Exception e){
System.out.println("catch");
return; // also tried with break; in switch-case, got same output
} finally {
System.out.println("finally");
}
SALIDA:
catch
finally
Teniendo en cuenta este código, ¿puedo estar absolutamente seguro de que el bloque finally
siempre se ejecuta, sin importar qué es something()
?
try {
something();
return success;
}
catch (Exception e) {
return failure;
}
finally {
System.out.println("i don''t know if this will get printed out.");
}
Además de las otras respuestas, es importante señalar que ''finalmente'' tiene el derecho de anular cualquier excepción / valor devuelto por el bloque try..catch. Por ejemplo, el siguiente código devuelve 12:
public static int getMonthsInYear() {
try {
return 10;
}
finally {
return 12;
}
}
Del mismo modo, el siguiente método no lanza una excepción:
public static int getMonthsInYear() {
try {
throw new RuntimeException();
}
finally {
return 12;
}
}
Mientras que el siguiente método lo lanza:
public static int getMonthsInYear() {
try {
return 12;
}
finally {
throw new RuntimeException();
}
}
Además del punto sobre el retorno al reemplazar finalmente un retorno en el bloque try, lo mismo ocurre con una excepción. Un bloque finalmente que lanza una excepción reemplazará una devolución o excepción lanzada desde dentro del bloque try.
Además, aunque es una mala práctica, si hay una declaración de retorno dentro del bloque finally, prevalecerá sobre cualquier otro retorno del bloque regular. Es decir, el siguiente bloque devolvería falso:
try { return true; } finally { return false; }
Lo mismo con lanzar excepciones del bloque finalmente.
Aquí están las palabras oficiales de la especificación del lenguaje Java.
14.20.2. Ejecución de try-finally y try-catch-finally
Una sentencia de
try
con un bloquefinally
se ejecuta ejecutando primero el bloque detry
. Entonces hay una opción:
- Si la ejecución del bloque
try
se completa normalmente, [...]- Si la ejecución del bloque
try
se completa abruptamente debido a unthrow
de un valor V , [...]- Si la ejecución del bloque
try
se completa abruptamente por cualquier otra razón R , entonces se ejecuta el bloquefinally
. Entonces hay una opción:
- Si el bloque finalmente se completa normalmente, entonces la instrucción
try
completa abruptamente por la razón R.- Si el bloque final 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 ).
La especificación para return
realmente hace esto explícito:
JLS 14.17 La declaración de retorno
ReturnStatement: return Expression(opt) ;
Una declaración de
return
sinExpression
intenta transferir el control al invocador del método o constructor que lo contiene.Una declaración de
return
con unaExpression
intenta transferir el control al invocador del método que lo contiene; El valor de laExpression
convierte en el valor de la invocación del método.Las descripciones anteriores dicen " intentos de transferir el control " en lugar de solo " transferencias de control " porque si hay alguna instrucción de
try
dentro del método o constructor cuyos bloques detry
contienen la instrucción dereturn
, entonces se ejecutarán las cláusulasfinally
de esas declaraciones detry
, en Orden, de lo más interno a lo más externo, antes de transferir el control al invocador del método o constructor. La finalización brusca de una cláusulafinally
puede interrumpir la transferencia de control iniciada por una declaración dereturn
.
Aquí hay una elaboración de la respuesta de Kevin . Es importante saber que la expresión que se devolverá se evalúa antes de finally
, incluso si se devuelve después.
public static void main(String[] args) {
System.out.println(Test.test());
}
public static int printX() {
System.out.println("X");
return 0;
}
public static int test() {
try {
return printX();
}
finally {
System.out.println("finally trumps return... sort of");
}
}
Salida:
X
finally trumps return... sort of
0
Código de ejemplo:
public static void main(String[] args) {
System.out.println(Test.test());
}
public static int test() {
try {
return 0;
}
finally {
System.out.println("finally trumps return.");
}
}
Salida:
finally trumps return.
0
Considere el siguiente programa:
public class someTest {
private static StringBuilder sb = new StringBuilder();
public static void main(String args[]) {
System.out.println(someString());
System.out.println("---AGAIN---");
System.out.println(someString());
}
private static String someString() {
try {
sb.append("-abc-");
return sb.toString();
} finally {
sb.append("xyz");
}
}
}
A partir de Java 1.8.162, el bloque de código anterior da el siguiente resultado:
-abc-
---AGAIN---
-abc-xyz-abc-
esto significa que usar finally
para liberar objetos es una buena práctica como el siguiente código:
private static String someString() {
StringBuilder sb = new StringBuilder();
try {
sb.append("abc");
return sb.toString();
} finally {
sb = null;
}
}
Considere esto en un curso normal de ejecución (es decir, sin que se lance ninguna excepción): si el método no es ''vacío'', entonces siempre devuelve algo explícitamente, sin embargo, finalmente, siempre se ejecuta
De manera concisa, en la documentación oficial de Java (Haga clic here ), está escrito que:
Si la JVM sale mientras se está ejecutando el código try o catch, entonces el bloque finally puede no ejecutarse. Del mismo modo, si el subproceso que ejecuta el código try o catch se interrumpe o se elimina, el bloque finally puede no ejecutarse aunque la aplicación en su totalidad continúe.
El bloque finally se ejecuta siempre a menos que haya una terminación anormal del programa, ya sea como resultado de un bloqueo de JVM o de una llamada a System.exit(0)
.
Además de eso, cualquier valor devuelto desde el bloque finally anulará el valor devuelto antes de la ejecución del bloque finally, así que tenga cuidado de verificar todos los puntos de salida al usar try finalmente.
Esa es toda la idea de un bloque finalmente. Le permite asegurarse de que realiza limpiezas que, de lo contrario, podrían omitirse porque, por supuesto, entre otras cosas, regresa.
Finalmente, recibe una llamada independientemente de lo que suceda en el bloque de prueba (a menos que llame a System.exit(int)
o la Máquina Virtual de Java salga por alguna otra razón).
Eso es realmente cierto en cualquier idioma ... finalmente, siempre se ejecutará antes de una declaración de devolución, sin importar dónde se encuentre esa devolución en el cuerpo del método. Si ese no fuera el caso, el bloque finalmente no tendría mucho significado.
Esto se debe a que asignó el valor de i como 12, pero no devolvió el valor de i a la función. El código correcto es el siguiente:
public static int test() {
int i = 0;
try {
return i;
} finally {
i = 12;
System.out.println("finally trumps return.");
return i;
}
}
Finalmente, el bloque siempre se ejecuta, ya sea que se trate de excepciones o no. Si se produjo alguna excepción antes del bloque de prueba, el bloque finalmente no se ejecutará.
Finalmente, siempre se ejecuta ese es todo el punto, solo porque aparece en el código después de la devolución no significa que así se implementa. El tiempo de ejecución de Java tiene la responsabilidad de ejecutar este código al salir del bloque try
.
Por ejemplo, si tiene lo siguiente:
int foo() {
try {
return 42;
}
finally {
System.out.println("done");
}
}
El tiempo de ejecución generará algo como esto:
int foo() {
int ret = 42;
System.out.println("done");
return 42;
}
Si se lanza una excepción no detectada, el bloque finally
se ejecutará y la excepción continuará propagándose.
No, no siempre un caso de excepción es // System.exit (0); Antes de que el bloque finalmente impida finalmente ser ejecutado.
class A {
public static void main(String args[]){
DataInputStream cin = new DataInputStream(System.in);
try{
int i=Integer.parseInt(cin.readLine());
}catch(ArithmeticException e){
}catch(Exception e){
System.exit(0);//Program terminates before executing finally block
}finally{
System.out.println("Won''t be executed");
System.out.println("No error");
}
}
}
Porque la final siempre se llama en cualquier caso que tengas. No tiene una excepción, todavía se llama, captura la excepción, todavía se llama
Porque siempre se llamará un bloque finally a menos que llames a System.exit()
(o el hilo se cuelgue).
Probé el ejemplo anterior con una ligera modificación.
public static void main(final String[] args) {
System.out.println(test());
}
public static int test() {
int i = 0;
try {
i = 2;
return i;
} finally {
i = 12;
System.out.println("finally trumps return.");
}
}
Las salidas del código anterior:
Finalmente triunfa el regreso.
2
Esto es porque cuando return i;
se ejecuta i
tiene un valor 2. Después de esto, se ejecuta el bloque finally
donde se asigna 12 a i
y luego se ejecuta System.out
.
Después de ejecutar el bloque finally
, el bloque try
devuelve 2, en lugar de devolver 12, porque esta instrucción de retorno no se ejecuta de nuevo.
Si va a depurar este código en Eclipse, tendrá la sensación de que, después de ejecutar System.out
finally
bloqueará la declaración de return
del bloque try
. Pero este no es el caso. Simplemente devuelve el valor 2.
Sí se llamará. Ese es el punto central de tener una palabra clave finalmente. Si saltarse fuera del bloque try / catch podría saltar el bloque final, sería lo mismo que poner System.out.println fuera del try / catch.
Sí, finally
se llamará después de la ejecución de los bloques de código try o catch.
Las únicas veces que finally
no se llamarán son:
- Si
System.exit()
; - Si la JVM se bloquea primero;
- Si la JVM alcanza un bucle infinito (o alguna otra instrucción no interrumpible, sin terminación) en el bloque
try
ocatch
; - Si el SO termina por la fuerza el proceso de JVM; por ejemplo, "kill -9" en UNIX.
- Si el sistema host muere; Por ejemplo, fallo de alimentación, error de hardware, pánico del sistema operativo, etc.
- Si finalmente el bloque va a ser ejecutado por el subproceso del daemon y todos los demás subprocesos que no son del demonio, antes de finalmente se llama.
Sí, finalmente el bloque siempre se ejecuta. La mayoría de los desarrolladores utilizan este bloque para cerrar la conexión de la base de datos, el objeto del conjunto de resultados, el objeto de declaración y también los utilizan en la hibernación de Java para revertir la transacción.
Si lo sera El único caso es que no es JVM sale o se bloquea
Si lo sera No importa lo que suceda en su bloque try / catch a menos que System.exit () sea llamado o JVM se bloquee. Si hay alguna declaración de devolución en el (los) bloque (es), finalmente se ejecutará antes de esa declaración de devolución.
Si se lanza una excepción, finalmente se ejecuta. Si no se lanza una excepción, finalmente se ejecuta. Si la excepción es atrapada, finalmente se ejecuta. Si la excepción no es atrapada, finalmente se ejecuta.
La única vez que no se ejecuta es cuando sale JVM.
También un retorno en finalmente tirará cualquier excepción. http://jamesjava.blogspot.com/2006/03/dont-return-in-finally-clause.html
Una manera lógica de pensar en esto es:
- El código colocado en un bloque finally debe ejecutarse lo que ocurra dentro del bloque try
- Por lo tanto, si el código en el bloque try intenta devolver un valor o lanzar una excepción, el elemento se coloca ''en el estante'' hasta que se pueda ejecutar el bloque finally
- Debido a que el código en el bloque finally tiene (por definición) una prioridad alta, puede devolver o lanzar lo que quiera. En cuyo caso, todo lo que quede "en el estante" se desecha.
- La única excepción a esto es si la VM se apaga completamente durante el bloque de prueba, por ejemplo, por ''System.exit''
Una manera lógica de pensar en esto es:
El código colocado en un bloque finally debe ejecutarse lo que ocurra dentro del bloque try.
Entonces, si el código en el bloque try intenta devolver un valor o lanzar una excepción, el elemento se coloca ''en el estante'' hasta que el bloque finally pueda ejecutarse. Debido a que el código en el bloque finally tiene (por definición) una prioridad alta, puede devolver o lanzar lo que le guste En cuyo caso, todo lo que quede "en el estante" se desecha.
La única excepción a esto es si la VM se apaga completamente durante el bloque de prueba, por ejemplo, por ''System.exit''
Nunca lanzar ninguna excepción desde el bloque finalmente
try {
someMethod(); //Throws exceptionOne
} finally {
cleanUp(); //If finally also threw any exception the exceptionOne will be lost forever
}
Esto está bien, siempre que cleanUp () nunca pueda lanzar ninguna excepción. En el ejemplo anterior, si someMethod () lanza una excepción, y también en el bloque finally, cleanUp () lanza una excepción, esa segunda excepción saldrá del método y la primera excepción original (razón correcta) se perderá para siempre. Si el código que llama en un bloque finally puede lanzar una excepción, asegúrese de que lo maneja o lo registra. Nunca dejes que salga del bloque finalmente.
En realidad, al salir del programa (ya sea llamando a System.exit () o causando un error fatal que causa que el proceso se interrumpa: algunas veces se hace referencia informalmente como un "punto de acceso" o "Dr Watson" en Windows) evitará que finalmente se bloquee ¡ejecutado!
No hay nada que nos impida anidar los bloqueos try / catch / finally (por ejemplo, poner un bloque try / finally dentro de un bloque try / catch, o viceversa), y no es algo tan inusual.
finalmente, siempre se ejecuta a menos que haya una terminación anormal del programa (como llamar a System.exit (0) ..). así, tu sysout se imprimirá