En una pregunta para Java en la universidad, había este fragmento de código:
class MyExc1 extends Exception {}
class MyExc2 extends Exception {}
class MyExc3 extends MyExc2 {}
public class C1 {
public static void main(String[] args) throws Exception {
try {
System.out.print(1);
q();
}
catch (Exception i) {
throw new MyExc2();
}
finally {
System.out.print(2);
throw new MyExc1();
}
}
static void q() throws Exception {
try {
throw new MyExc1();
}
catch (Exception y) {
}
finally {
System.out.print(3);
throw new Exception();
}
}
}
Me pidieron que diera su salida. Respondí 13Exception in thread main MyExc2
, pero la respuesta correcta es 132Exception in thread main MyExc1
. ¿Por qué es eso? Simplemente no puedo entender a dónde MyExc2
va.
Esto es lo que dice Wikipedia sobre la cláusula finalmente:
Analicemos su programa.
Por lo tanto, se
1
mostrará en la pantalla, luegoq()
se llama. Enq()
, se lanza una excepción. La excepción queda atrapadaException y
pero no hace nada. A finalmente se ejecuta entonces cláusula (tiene que), por lo que,3
se va a imprimir a la pantalla. Debido a que (en el métodoq()
hay una excepción lanzada en la cláusula finalmente , también elq()
método pasa la excepción a la pila principal (mediante lathrows Exception
declaración en el método)new Exception()
será lanzada y atrapadacatch ( Exception i )
, seMyExc2
lanzará una excepción (por ahora agréguela a la pila de excepciones) ), pero finalmentemain
se ejecutará un finalmente en el bloque.Entonces en
Una cláusula finalmente se llama ... (recuerde, acabamos de atrapar
Exception i
y lanzarMyExc2
) en esencia,2
se imprime en la pantalla ... y después de que2
se imprime en la pantalla,MyExc1
se lanza una excepción.MyExc1
se maneja por elpublic static void main(...)
métodoSalida:
Profesor es correcto! :-)
En esencia , si finalmente tiene una cláusula try / catch, se ejecutará un finalmente ( después de atrapar la excepción antes de descartar la excepción atrapada)
fuente
catch
se ejecuta desde queq()
lanzó unException
desde su propiofinally
bloque.q
pasa la ejecución acatch
bloque vacío enq
(que se traga esta excepción), luego alfinally
bloque enq
. Dicho bloque finalmente imprime3
, luego lanza una nueva excepción, que gracias aq
'sthrows Exception
se pasa por la pila al padre.Las excepciones en el bloque finalmente reemplazan las excepciones en el bloque catch.
Citando de la edición 14 de Java Language Specification :
fuente
Finalmente, la cláusula se ejecuta incluso cuando se lanza una excepción desde cualquier parte del bloque try / catch.
Debido a que es el último en ejecutarse en el
main
y arroja una excepción, esa es la excepción que ven las personas que llaman.De ahí la importancia de asegurarse de que la
finally
cláusula no arroje nada, ya que puede tragar excepciones deltry
bloque.fuente
Una
method
no puedethrow
dos excepciones al mismo tiempo. Siempre lanzará el último lanzamientoexception
, que en este caso siempre será el delfinally
bloque.Cuando
q()
se lanza la primera excepción del método , se atrapará y luego será tragada por la excepción lanzada finalmente bloqueada.q () -> arrojado
new Exception
->main
catch Exception
->throw
new Exception
->finally
lanzar un nuevoexception
(y el delcatch
"se pierde")fuente
La forma más fácil de pensar en esto es imaginar que hay una variable global para toda la aplicación que contiene la excepción actual.
A medida que se produce cada excepción, "currentException" se establece en esa excepción. Cuando finaliza la aplicación, si currentException es! = Nulo, el tiempo de ejecución informa el error.
Además, los bloques finalmente siempre se ejecutan antes de que salga el método. Luego puede solicitar el fragmento de código a:
El orden en que se ejecuta la aplicación es:
fuente
Es bien sabido que el bloque finalmente se ejecuta después de intentar y atrapar y siempre se ejecuta ... Pero como viste, es un poco complicado a veces echa un vistazo a ese fragmento de código a continuación y verás que las declaraciones de devolución y lanzamiento no No siempre hagas lo que deberían hacer en el orden que esperamos que haga el tema.
Salud.
fuente
Orden:
https://www.compilejava.net/
fuente
La lógica es clara hasta que termine de imprimirse
13
. Entonces la excepción lanzada enq()
es capturado porcatch (Exception i)
enmain()
ynew MyEx2()
está listo para ser lanzado. Sin embargo, antes de lanzar la excepción, elfinally
bloque debe ejecutarse primero. Entonces la salida se convierte132
yfinally
pide lanzar otra excepciónnew MyEx1()
.Como un método no puede lanzar más de uno
Exception
, siempre arrojará lo últimoException
. En otras palabras, si amboscatch
y losfinally
bloques intentan lanzarException
, entoncesException
se traga la captura y solo sefinally
lanzará la excepción .Por lo tanto, en este programa, la excepción
MyEx2
se traga yMyEx1
se lanza. Esta excepción se expulsamain()
y ya no se captura, por lo que JVM se detiene y el resultado final es132Exception in thread main MyExc1
.En esencia, si tiene un
finally
en unatry/catch
cláusula,finally
se ejecutará un DESPUÉS de atrapar la excepción , pero ANTES de lanzar cualquier excepción atrapada , y SOLAMENTE la última excepción se lanzará al final .fuente
Creo que solo tienes que caminar los
finally
bloques:finally
enq
impresión "3".finally
enmain
impresión "2".fuente
Para manejar este tipo de situación, es decir, manejar la excepción planteada por finalmente bloquear. Puedes rodear el bloque finalmente por el bloque try: mira el siguiente ejemplo en python:
fuente
Creo que esto resuelve el problema:
fuente