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 MyExc2va.

Esto es lo que dice Wikipedia sobre la cláusula finalmente:
Analicemos su programa.
Por lo tanto, se
1mostrará en la pantalla, luegoq()se llama. Enq(), se lanza una excepción. La excepción queda atrapadaException ypero no hace nada. A finalmente se ejecuta entonces cláusula (tiene que), por lo que,3se 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 Exceptiondeclaración en el método)new Exception()será lanzada y atrapadacatch ( Exception i ), seMyExc2lanzará una excepción (por ahora agréguela a la pila de excepciones) ), pero finalmentemainse ejecutará un finalmente en el bloque.Entonces en
Una cláusula finalmente se llama ... (recuerde, acabamos de atrapar
Exception iy lanzarMyExc2) en esencia,2se imprime en la pantalla ... y después de que2se imprime en la pantalla,MyExc1se lanza una excepción.MyExc1se 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
catchse ejecuta desde queq()lanzó unExceptiondesde su propiofinallybloque.qpasa la ejecución acatchbloque vacío enq(que se traga esta excepción), luego alfinallybloque enq. Dicho bloque finalmente imprime3, luego lanza una nueva excepción, que gracias aq'sthrows Exceptionse 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
mainy arroja una excepción, esa es la excepción que ven las personas que llaman.De ahí la importancia de asegurarse de que la
finallycláusula no arroje nada, ya que puede tragar excepciones deltrybloque.fuente
Una
methodno puedethrowdos excepciones al mismo tiempo. Siempre lanzará el último lanzamientoexception, que en este caso siempre será el delfinallybloque.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->maincatch Exception->thrownew Exception->finallylanzar 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, elfinallybloque debe ejecutarse primero. Entonces la salida se convierte132yfinallypide 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 amboscatchy losfinallybloques intentan lanzarException, entoncesExceptionse traga la captura y solo sefinallylanzará la excepción .Por lo tanto, en este programa, la excepción
MyEx2se traga yMyEx1se 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
finallyen unatry/catchcláusula,finallyse 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
finallybloques:finallyenqimpresión "3".finallyenmainimpresió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