Em uma pergunta para Java na universidade, havia este trecho 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 pediram para dar sua saída. Eu respondi 13Exception in thread main MyExc2
, mas a resposta correta é 132Exception in thread main MyExc1
. Por que é isso? Eu simplesmente não consigo entender para onde MyExc2
vai.
Isto é o que a Wikipedia diz sobre finalmente a cláusula:
Vamos dissecar seu programa.
Então,
1
será emitido na tela e, em seguida,q()
é chamado. Emq()
, uma exceção é lançada. A exceção é capturada,Exception y
mas não faz nada. Uma cláusula finalmente é executada (precisa), portanto,3
será impressa na tela. Como (no métodoq()
há uma exceção lançada na cláusula finally , também oq()
método passa a exceção para a pilha pai (pelathrows Exception
declaração na método)new Exception()
será lançada e capturada porcatch ( Exception i )
, aMyExc2
exceção será lançada (por enquanto, adicione-a à pilha de exceções ), mas um finalmente nomain
bloco será executado primeiro.Então,
Uma cláusula finalmente é chamada ... (lembre-se, acabamos de capturar
Exception i
e lançarMyExc2
) em essência,2
é impressa na tela ... e após a2
impressão na tela, umaMyExc1
exceção é lançada.MyExc1
é tratado pelopublic static void main(...)
métodoResultado:
Palestrante está correto! :-)
Em essência , se você tiver uma cláusula finalmente em uma tentativa / captura, uma finalmente será executada ( após capturar a exceção antes de lançar a exceção capturada)
fonte
catch
é executado desde queq()
lançou umException
de seu própriofinally
bloco.q
passa a execução para ocatch
bloco vazioq
(que engole essa exceção) e depois nofinally
blocoq
. O dito finalmente bloqueia as impressões e3
, em seguida, lança uma nova exceção, que graças aq
'sthrows Exception
é passada para cima pela pilha para o pai.As exceções no bloco final substituem as exceções no bloco de captura.
Citando a partir da edição Java Language Specification 14 :
fonte
Finalmente, a cláusula é executada mesmo quando a exceção é lançada de qualquer lugar no bloco try / catch.
Como é o último a ser executado no
main
e gera uma exceção, essa é a exceção que os chamadores veem.Daí a importância de garantir que a
finally
cláusula não atinja nada, pois ela pode engolir exceções dotry
bloco.fonte
A
method
não podethrow
duas exceções ao mesmo tempo. Ele sempre jogará o último arremessoexception
, que neste caso será sempre o dofinally
bloco.Quando a primeira exceção do método
q()
é lançada, ela será capturada e depois engolida pela exceção finalmente lançada pelo bloco.q () -> jogado
new Exception
->main
catch Exception
->throw
new Exception
->finally
jogue um novoexception
(e aquele docatch
é "perdido")fonte
A maneira mais fácil de pensar nisso é imaginar que haja uma variável global em todo o aplicativo que esteja mantendo a exceção atual.
À medida que cada exceção é lançada, "currentException" é definido para essa exceção. Quando o aplicativo termina, se currentException for! = Null, o tempo de execução relata o erro.
Além disso, os blocos finalmente sempre são executados antes da saída do método. Você pode solicitar o snippet de código para:
A ordem em que o aplicativo é executado é:
fonte
É sabido que o bloco final é executado após o try and catch e sempre é executado ... Mas como você viu, é um pouco complicado às vezes, verifique o trecho de código abaixo e você verá que as instruções return e throw não sempre faça o que eles devem fazer na ordem que esperamos que o tema faça.
Felicidades.
fonte
Ordem:
https://www.compilejava.net/
fonte
A lógica é clara até terminar a impressão
13
. Em seguida, a exceção lançada emq()
é capturado porcatch (Exception i)
nosmain()
e umanew MyEx2()
está pronta para ser lançada. No entanto, antes de lançar a exceção, ofinally
bloco deve ser executado primeiro. Em seguida, a saída se torna132
efinally
pede para lançar outra exceçãonew MyEx1()
.Como um método não pode lançar mais de um
Exception
, sempre lançará o mais recenteException
. Em outras palavras, se os doiscatch
e osfinally
blocos tentarem jogarException
, aException
captura de entrada será engolida e somente a exceçãofinally
será lançada.Assim, neste programa, a exceção
MyEx2
é engolida eMyEx1
lançada. Essa exceção é lançadamain()
e não é mais capturada, portanto, a JVM para e a saída final é132Exception in thread main MyExc1
.Em essência, se você tiver a
finally
em umatry/catch
cláusula, afinally
será executada APÓS capturar a exceção , mas antes de lançar qualquer exceção capturada , e somente a exceção mais recente seria lançada no final .fonte
Eu acho que você só precisa andar pela
finally
quarteirões:finally
noq
impressão "3".finally
namain
impressão "2".fonte
Para lidar com esse tipo de situação, ou seja, manipular a exceção gerada pelo bloco finalmente. Você pode colocar o bloco final usando o bloco try: Veja o exemplo abaixo em python:
fonte
Eu acho que isso resolve o problema:
fonte