Nota: Se a JVM sair enquanto o código try ou catch está sendo executado, o bloco finally pode não ser executado. Da mesma forma, se o encadeamento que executa o código try ou catch for interrompido ou eliminado, o bloco finally pode não ser executado mesmo que o aplicativo como um todo continue.
Não conheço nenhuma outra maneira de o bloco finally não ser executado ...
@dhiller - Tenho certeza de que "desligar" está incluído em "Se a JVM sair ..." :-p
Jason Coco
2
@Jason Coco: Terminar (como na perda de energia) não é exatamente a mesma coisa que sair; o último é um processo mais ou menos organizado que culmina no primeiro. ; p
user359996
2
AFAIK, se um tópico é interrompido, não é interrompido imediatamente. Cabe ao código no thread detectar a interrupção e parar sua tarefa, então, finalmente, o código deve ser executado.
Bart van Heukelom
2
Eu acho que se uma exceção for lançada no bloco finally, o resto do bloco não será executado.
Encerra a Java Virtual Machine atualmente em execução. O argumento serve como um código de status; por convenção, um código de status diferente de zero indica encerramento anormal.
Este método chama o exitmétodo em classe Runtime. Este método nunca retorna normalmente.
Além disso, uma exceção deve desligar o Java Virtual Machine.
kaissun de
3
Se uma exceção ocorrer durante a execução de System.exit (0), então o bloco finalmente será executado.
Halil
50
Apenas para expandir o que os outros disseram, qualquer coisa que não cause algo como a saída da JVM incorrerá no bloqueio finally. Portanto, o seguinte método:
isso realmente me confundiu por um bom par de horas algumas semanas atrás.
nickf
3
É considerado uma má ideia retornar um valor de um bloco finally. Retorne apenas do bloco try ou retorne de fora do bloco try / finally. A maioria dos IDEs marcará isso com um aviso.
Ran Biron
1
@nickf Percebi que você não está mais confuso. Você poderia explicar a mecânica de por que 1 é retornado e não 0. Eu só poderia adivinhar que a memória (ou é um registro) que armazena o valor de retorno da função que inicialmente contém 0, é sobrescrita quando o bloco finally é executado .
Yaneeve
2
Isso é curioso, em C # não é permitido retornar de um bloco finally.
JMCF125
3
@RanBiron Claro. Ele não estava realmente recomendando retornar dentro de um bloco finally, ele estava apenas tentando demonstrar que mesmo uma instrução return ainda fará com que o código desse bloco seja executado.
Aquarelle
15
Relacionado a System.exit, também existem certos tipos de falha catastrófica em que um bloco final pode não ser executado. Se a JVM ficar totalmente sem memória, ela pode simplesmente sair sem travar ou finalmente acontecer.
Especificamente, lembro-me de um projeto em que tentamos tolamente usar
catch(OutOfMemoryError oome){// do stuff}
Isso não funcionou porque a JVM não tinha mais memória para executar o bloco catch.
Quando OutOfMemoryError é lançado, geralmente há muita memória restante (para interromper o thrashing do GC). No entanto, se você pegá-lo repetidamente, obviamente retornará ao problema do GC.
Tom Hawtin - tackline
Achei que não se deveria pegar exceções não verificadas!
Sergii Shevchyk
1
Tentei do meu lado, usando jdk7, mas pegou o erro OutOfMemory!
Jaskey
10
try{for(;;);}finally{System.err.println("?");}
Nesse caso, o finally não será executado (a menos que o obsoleto Thread.stopseja chamado, ou um equivalente, digamos, por meio de uma interface de ferramentas).
Eu não acho que haja um problema. Talvez você esteja imaginando uma captura que não existe. Se inserirmos um explícito throw, o finallybloco será executado conforme o esperado. try { throw new ThreadDeath(); } finally { System.err.println("?"); }
Tom Hawtin - tackline
9
O tutorial do Sun foi citado erroneamente aqui neste tópico.
Nota: Se a JVM sair enquanto o código try ou catch estiver sendo executado, o bloco finally não será executado. Da mesma forma, se o thread que executa o código try ou catch for interrompido ou eliminado, o bloco finally irá não executado, embora o aplicativo como um todo continue.
Se você olhar atentamente para o tutorial do sol para o bloco final, ele não diz "não será executado", mas "pode não ser executado" Aqui está a descrição correta
Nota: Se a JVM sair enquanto o código try ou catch está sendo executado, o bloco finally pode não ser executado. Da mesma forma, se o encadeamento que executa o código try ou catch for interrompido ou eliminado, o bloco finally pode não ser executado mesmo que o aplicativo como um todo continue.
A razão aparente para esse comportamento é que a chamada para system.exit () é processada em um thread do sistema em tempo de execução que pode demorar para desligar o jvm, enquanto o planejador de thread pode finalmente pedir para ser executado. Então, finalmente, é projetado para executar sempre, mas se você estiver encerrando o jvm, pode acontecer que o jvm seja encerrado antes de finalmente ser executado.
Tecnicamente, o bloco try nunca sai, então o bloco finally nunca deve ter a chance de ser executado. O mesmo pode ser dito para um loop infinito.
Jeff Mercado
6
Se a JVM sair enquanto o código try ou catch estiver sendo executado, o bloco finally pode não ser executado. ( fonte )
Desligamento normal - isso ocorre quando o último segmento não-daemon sai OU quando Runtime.exit () ( fonte )
Quando um encadeamento é encerrado, a JVM executa um inventário de encadeamentos em execução e, se os únicos encadeamentos restantes forem encadeamentos daemon, ele inicia um encerramento ordenado. Quando a JVM é interrompida, quaisquer encadeamentos de daemon restantes são abandonados, finalmente os blocos não são executados, as pilhas não são desenroladas, a JVM apenas sai. Os encadeamentos daemon devem ser usados com moderação; poucas atividades de processamento podem ser abandonadas com segurança a qualquer momento, sem limpeza. Em particular, é perigoso usar threads de daemon para tarefas que podem realizar qualquer tipo de E / S. Os encadeamentos daemon são melhor salvos para tarefas de "manutenção", como um encadeamento em segundo plano que remove entradas expiradas periodicamente de um cache na memória. ( fonte )
Exemplo de últimas saídas de thread não daemon:
publicclassTestDaemon{privatestaticRunnable runnable =newRunnable(){@Overridepublicvoid run(){try{while(true){System.out.println("Is alive");Thread.sleep(10);// throw new RuntimeException();}}catch(Throwable t){
t.printStackTrace();}finally{System.out.println("This will never be executed.");}}};publicstaticvoid main(String[] args)throwsInterruptedException{Thread daemon =newThread(runnable);
daemon.setDaemon(true);
daemon.start();Thread.sleep(100);// daemon.stop();System.out.println("Last non-daemon thread exits.");}}
Resultado:
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Last non-daemon thread exits.Is alive
Is alive
Is alive
Is alive
Is alive
Existem duas maneiras de parar finalmente a execução do código:
1. Use System.exit ();
2. Se de alguma forma, o controle de execução não chega a tentar bloquear.
Vejo:
publicclassMain{publicstaticvoid main (String[]args){if(true){System.out.println("will exceute");}else{try{System.out.println("result = "+5/0);}catch(ArithmeticException e){System.out.println("will not exceute");}finally{System.out.println("will not exceute");}}}}
Eu me deparei com um caso muito específico do bloco finally não executando, relacionado especificamente à estrutura de reprodução.
Fiquei surpreso ao descobrir que o bloco finally neste código de ação do controlador só foi chamado depois de uma exceção, mas nunca quando a chamada realmente foi bem-sucedida.
try{InputStream is = getInputStreamMethod();
renderBinary(is,"out.zip");catch(Exception e){
e.printStackTrace();}finally{
cleanUp();}
Talvez o thread seja encerrado ou algo assim quando renderBinary () é chamado. Eu suspeitaria que a mesma coisa acontece com outras chamadas render (), mas não verifiquei isso.
Resolvi o problema movendo renderBinary () para depois de try / catch. Uma investigação mais aprofundada revelou que play fornece uma anotação @Finally para criar um método que é executado após a execução de uma ação do controlador. A ressalva aqui é que ele será chamado após a execução de QUALQUER ação no controlador, portanto, nem sempre é uma boa escolha.
//If ArithmeticException Occur Inner finally would not be executedclassTemp{publicstaticvoid main(String[] s){try{int x =10/s.length;System.out.println(x);try{int z[]=newint[s.length];
z[10]=1000;}catch(ArrayIndexOutOfBoundsException e){System.out.println(e);}finally{System.out.println("Inner finally");}}catch(ArithmeticException e){System.out.println(e);}finally{System.out.println("Outer Finally");}System.out.println("Remaining Code");}}
Respostas:
dos tutoriais da Sun
Não conheço nenhuma outra maneira de o bloco finally não ser executado ...
fonte
System.exit desliga a máquina virtual.
"bye" não é impresso no código acima.
fonte
Apenas para expandir o que os outros disseram, qualquer coisa que não cause algo como a saída da JVM incorrerá no bloqueio finally. Portanto, o seguinte método:
irá estranhamente compilar e retornar 1.
fonte
Relacionado a System.exit, também existem certos tipos de falha catastrófica em que um bloco final pode não ser executado. Se a JVM ficar totalmente sem memória, ela pode simplesmente sair sem travar ou finalmente acontecer.
Especificamente, lembro-me de um projeto em que tentamos tolamente usar
Isso não funcionou porque a JVM não tinha mais memória para executar o bloco catch.
fonte
Nesse caso, o finally não será executado (a menos que o obsoleto
Thread.stop
seja chamado, ou um equivalente, digamos, por meio de uma interface de ferramentas).fonte
throw
, ofinally
bloco será executado conforme o esperado.try { throw new ThreadDeath(); } finally { System.err.println("?"); }
O tutorial do Sun foi citado erroneamente aqui neste tópico.
Nota: Se a JVM sair enquanto o código try ou catch estiver sendo executado, o bloco finally não será executado. Da mesma forma, se o thread que executa o código try ou catch for interrompido ou eliminado, o bloco finally irá não executado, embora o aplicativo como um todo continue.
Se você olhar atentamente para o tutorial do sol para o bloco final, ele não diz "não será executado", mas "pode não ser executado" Aqui está a descrição correta
A razão aparente para esse comportamento é que a chamada para system.exit () é processada em um thread do sistema em tempo de execução que pode demorar para desligar o jvm, enquanto o planejador de thread pode finalmente pedir para ser executado. Então, finalmente, é projetado para executar sempre, mas se você estiver encerrando o jvm, pode acontecer que o jvm seja encerrado antes de finalmente ser executado.
fonte
Além disso, se um deadlock / livelock acontecer dentro
try
bloco.Aqui está o código que demonstra isso:
Este código produz a seguinte saída:
e "finalmente" nunca é impresso
fonte
Se a JVM sair enquanto o código try ou catch estiver sendo executado, o bloco finally pode não ser executado. ( fonte )
Desligamento normal - isso ocorre quando o último segmento não-daemon sai OU quando Runtime.exit () ( fonte )
Quando um encadeamento é encerrado, a JVM executa um inventário de encadeamentos em execução e, se os únicos encadeamentos restantes forem encadeamentos daemon, ele inicia um encerramento ordenado. Quando a JVM é interrompida, quaisquer encadeamentos de daemon restantes são abandonados, finalmente os blocos não são executados, as pilhas não são desenroladas, a JVM apenas sai. Os encadeamentos daemon devem ser usados com moderação; poucas atividades de processamento podem ser abandonadas com segurança a qualquer momento, sem limpeza. Em particular, é perigoso usar threads de daemon para tarefas que podem realizar qualquer tipo de E / S. Os encadeamentos daemon são melhor salvos para tarefas de "manutenção", como um encadeamento em segundo plano que remove entradas expiradas periodicamente de um cache na memória. ( fonte )
Exemplo de últimas saídas de thread não daemon:
Resultado:
fonte
Nos seguintes casos, o bloco final não será executado: -
System.exit(0)
é invocado dotry
bloco.try
blocoTambém pode haver outros casos marginais, onde o bloco final não será executado.
fonte
Existem duas maneiras de parar finalmente a execução do código:
1. Use System.exit ();
2. Se de alguma forma, o controle de execução não chega a tentar bloquear.
Vejo:
fonte
Eu me deparei com um caso muito específico do bloco finally não executando, relacionado especificamente à estrutura de reprodução.
Fiquei surpreso ao descobrir que o bloco finally neste código de ação do controlador só foi chamado depois de uma exceção, mas nunca quando a chamada realmente foi bem-sucedida.
Talvez o thread seja encerrado ou algo assim quando renderBinary () é chamado. Eu suspeitaria que a mesma coisa acontece com outras chamadas render (), mas não verifiquei isso.
Resolvi o problema movendo renderBinary () para depois de try / catch. Uma investigação mais aprofundada revelou que play fornece uma anotação @Finally para criar um método que é executado após a execução de uma ação do controlador. A ressalva aqui é que ele será chamado após a execução de QUALQUER ação no controlador, portanto, nem sempre é uma boa escolha.
fonte
fonte