Faz um bloco finally sempre é executado em Java?
-
09-06-2019 - |
Pergunta
Considerando-se este código, pode ser eu certeza absoluta que o finally
bloco realiza sempre, não importa o que something()
o que é?
try {
something();
return success;
}
catch (Exception e) {
return failure;
}
finally {
System.out.println("I don't know if this will get printed out");
}
Solução
Sim, finally
será chamado após a execução do try
ou catch
blocos de código.
As únicas vezes finally
não seja chamada são:
- Se você chamar
System.exit()
- Se a JVM falha primeiro
- Se a JVM atinge um loop infinito (ou algum outro não interruptable, não-encerramento da instrução) no
try
oucatch
bloco - Se o sistema operacional forçosamente termina a JVM processo;por exemplo,
kill -9 <pid>
no UNIX - Se o sistema host morre;por exemplo, falha de energia, erro de hardware, sistema operacional do pânico, et cetera
- Se o
finally
bloco vai ser executado por um thread daemon e todos os outros não-daemon threads sair antesfinally
é chamado de
Outras dicas
Exemplo de código:
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.");
}
}
Saída:
finally trumps return.
0
Além disso, apesar da má prática, se houver uma instrução return dentro do bloco finally, ele vai trump qualquer outro retorno da regular bloco.Isto é, o bloco a seguir retornará falso:
try { return true; } finally { return false; }
Mesma coisa com gerar exceções do bloco finally.
Aqui está o oficial palavras a partir da Especificação da Linguagem Java.
14.20.2.Execução de try-finally e try-catch-finalmente
Um
try
declaraçãofinally
o bloco é executado pela primeira executar otry
bloco.Em seguida, há uma escolha:
- Se a execução do
try
bloco conclui normalmente, [...]- Se a execução do
try
bloco conclui abruptamente devido a umthrow
de um valor V, [...]- Se a execução do
try
bloco conclui abruptamente por qualquer outro motivo R, e , em seguida, ofinally
o bloco é executado.Em seguida, há uma escolha:
- Se o bloco finally conclui normalmente, em seguida, o
try
instrução conclui abruptamente para razão R.- Se o
finally
bloco conclui abruptamente para razão S, e , em seguida, otry
instrução conclui abruptamente para razão S (e a razão R é descartada).
A especificação para return
na verdade, torna isso explícito:
JLS 14.17 A Instrução de retorno
ReturnStatement: return Expression(opt) ;
Um
return
sem instruçãoExpression
tentativas para transferir o controle para o chamador do método ou construtor que o contém.Um
return
declaraçãoExpression
tentativas para transferir o controle para o chamador do método que o contém;o valor daExpression
torna-se o valor da invocação de método.Anterior descrições dizer "tentativas para transferir o controle"ao invés de apenas "controle de transferências de"porque, se há qualquer
try
instruções dentro do método ou construtor, cujatry
blocos de conter areturn
declaração, em seguida, qualquerfinally
as cláusulas dessestry
declarações será executada, a fim de, mais interno para o mais externo, antes que o controle é transferido para o chamador do método ou construtor.Abrupta conclusão de umfinally
cláusula pode interromper a transferência de controle iniciada por umreturn
instrução.
Além de outras respostas, é importante ressaltar que 'finalmente' tem o direito de substituir qualquer exceção/valor retornado pelo try..catch bloco.Por exemplo, o código a seguir retorna 12:
public static int getMonthsInYear() {
try {
return 10;
}
finally {
return 12;
}
}
Da mesma forma, o método a seguir não lança uma exceção:
public static int getMonthsInYear() {
try {
throw new RuntimeException();
}
finally {
return 12;
}
}
Enquanto o método a seguir não jogá-lo:
public static int getMonthsInYear() {
try {
return 12;
}
finally {
throw new RuntimeException();
}
}
Eu tentei o exemplo acima com ligeira modificação-
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.");
}
}
O código acima saídas:
finalmente supera a de regresso.
2
Isto é porque quando return i;
é executado i
tem um valor de 2.Depois disso o finally
o bloco é executado, onde 12 é atribuído a i
e, em seguida, System.out
out é executado.
Depois de executar o finally
bloco a try
bloco retorna 2, ao invés de retornar para 12, porque este retorno instrução não é executada novamente.
Se você depurar código no Eclipse, em seguida, você terá a sensação de que depois de executar System.out
de finally
bloco a return
instrução de try
o bloco é executado novamente.Mas este não é o caso.Ele simplesmente retorna o valor 2.
Aqui está uma elaboração de A resposta de Kevin.É importante saber que a expressão a ser devolvido é avaliada antes finally
, mesmo se ele for devolvido depois.
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");
}
}
Saída:
X
finally trumps return... sort of
0
Que é a idéia de um bloco finally.Ele permite que você certifique-se de que você fazer limpezas que poderiam ser ignorados, porque você voltar, entre outras coisas, é claro.
Finalmente é chamado independentemente do que acontece no bloco try (a menos que você chamar System.exit(int)
ou a Máquina Virtual de Java chutes de fora por algum outro motivo).
Um caminho lógico para pensar sobre isso é:
- Código colocado em um bloco finally deve ser executado o que ocorre dentro do bloco try
- Assim, se o código no bloco try tenta retornar um valor ou lançar uma exceção o item é colocado 'na prateleira' até o bloco finally pode executar
- Porque o código do bloco finally tem (por definição), uma alta prioridade, ele pode retornar ou jogar tudo o que ele gosta.Caso em que qualquer coisa de esquerda 'na prateleira' é descartada.
- A única exceção a isso é se o VM é completamente desligado durante o bloco try e.g.por 'Sistema.sair'
Também um retorno no fim deite fora qualquer exceção. http://jamesjava.blogspot.com/2006/03/dont-return-in-finally-clause.html
finalmente, sempre é executado, a menos que haja término anormal do programa (como a chamada de Sistema.exit(0)..).assim, o seu sysout será impresso
O bloco finally sempre é executado, a menos que haja término anormal do programa, seja resultante de uma falha JVM, ou a partir de uma chamada para System.exit(0)
.
No topo do que, qualquer valor retornado dentro do bloco finally será substituir o valor devolvido antes da execução do bloco finally, para ter o cuidado de verificar todos os pontos de saída quando usando tentar finalmente.
Não, nem sempre é um caso de exceção é// Do sistema.exit(0);antes de o bloco finally impede que, finalmente, para ser executado.
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");
}
}
}
Finalmente, é sempre executado, que é o ponto inteiro, só porque ele aparece no código, após o retorno não significa que essa é a forma como é implementado.O Java runtime tem a responsabilidade de executar este código quando sair o try
bloco.
Por exemplo, se você tem o seguinte:
int foo() {
try {
return 42;
}
finally {
System.out.println("done");
}
}
O runtime irá gerar algo como isto:
int foo() {
int ret = 42;
System.out.println("done");
return 42;
}
Se uma exceção não identificada é lançada a finally
bloco será executado e a exceção vai continuar a propagar.
Isso é porque você atribuído o valor de i, 12, mas não retornou o valor de i para a função.O código correto é o seguinte:
public static int test() {
int i = 0;
try {
return i;
} finally {
i = 12;
System.out.println("finally trumps return.");
return i;
}
}
Porque um bloco finally sempre será chamado, a menos que você chamar System.exit()
(ou o thread de falha).
A resposta é simples SIM.
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");
}
SAÍDA:
catch
finally
Sim ele será chamado.Esse é o ponto de ter um, finalmente, a palavra-chave.Se pulando para fora do bloco try/catch poderia simplesmente ignorar o bloco finally era o mesmo que colocar o Sistema.de fora.println fora o try/catch.
De forma concisa, oficial da Documentação do Java (Clique aqui), está escrito que -
Se a JVM termina enquanto o try ou catch código está sendo executado e, em seguida, o bloco finally não pode executar.Da mesma forma, se o thread de execução o try ou catch código é interrompido ou morto, o bloco finally pode não execute o mesmo que o aplicativo como um todo continua.
Sim, o bloco finally é sempre executado.A maioria de uso do desenvolvedor do bloco a de fechar a conexão de banco de dados, objeto resultset, declaração de objeto e também usa para o java, hibernate para reverter a transação.
Sim, ele vai.Não importa o que acontece no seu try ou catch bloco, a menos que de outra forma de Sistema.exit() chamado ou JVM caiu.se não houver qualquer instrução return no bloco(s),finalmente vai ser executado antes de que a instrução de retorno.
Sim Ele.Apenas caso não é JVM sai ou falha
Considere o seguinte 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());
System.out.println("---PRINT THE RESULT---");
System.out.println(sb.toString());
}
private static String someString() {
try {
sb.append("-abc-");
return sb.toString();
} finally {
sb.append("xyz");
}
}
}
Como de Java 1.8.162, acima bloco de código fornece a seguinte saída:
-abc-
---AGAIN---
-abc-xyz-abc-
---PRINT THE RESULT---
-abc-xyz-abc-xyz
isto significa que, usando finally
para liberar objetos é uma boa prática, como o código a seguir:
private static String someString() {
StringBuilder sb = new StringBuilder();
try {
sb.append("abc");
return sb.toString();
} finally {
sb = null; // Just an example, but you can close streams or DB connections this way.
}
}
Isto é uma verdade em qualquer idioma...finally sempre será executado antes de uma instrução de retorno, não importa onde o retorno é no corpo do método.Se esse não era o caso, o bloco finally não teria muito significado.
finally
irá executar e que é, com certeza.
finally
não será executado em casos abaixo:
caso 1 :
Quando você está executando System.exit()
.
caso 2 :
Quando a sua JVM / Thread falha.
caso 3 :
Quando sua execução é interrompida entre manualmente.
Se você não tratar de exceção, antes de encerrar o programa, a JVM executa bloco finally.Ele não será executado somente se a execução normal do programa irá falhar significa o término do programa, devido às seguintes razões..
Por causar um erro fatal que faz com que o processo de anulação.
Término do programa devido à memória corrompido.
Chamando Sistema.exit()
Se o programa entra em loop infinito.
Sim, porque nenhuma declaração de controle de pode impedir finally
de ser executada.
Aqui é uma referência exemplo, onde todos os blocos de código será executado:
| x | Current result | Code
|---|----------------|------ - - -
| | |
| | | public static int finallyTest() {
| 3 | | int x = 3;
| | | try {
| | | try {
| 4 | | x++;
| 4 | return 4 | return x;
| | | } finally {
| 3 | | x--;
| 3 | throw | throw new RuntimeException("Ahh!");
| | | }
| | | } catch (RuntimeException e) {
| 4 | return 4 | return ++x;
| | | } finally {
| 3 | | x--;
| | | }
| | | }
| | |
|---|----------------|------ - - -
| | Result: 4 |
Na variante abaixo, return x;
será ignorado.O resultado é ainda 4
:
public static int finallyTest() {
int x = 3;
try {
try {
x++;
if (true) throw new RuntimeException("Ahh!");
return x; // skipped
} finally {
x--;
}
} catch (RuntimeException e) {
return ++x;
} finally {
x--;
}
}
Referências, é claro, de acompanhar o seu status.Este exemplo retorna uma referência com value = 4
:
static class IntRef { public int value; }
public static IntRef finallyTest() {
IntRef x = new IntRef();
x.value = 3;
try {
return x;
} finally {
x.value++; // will be tracked even after return
}
}
try
- catch
- finally
são as palavras chave para o uso de manipulação de exceção do caso.
Como normal explanotory
try {
//code statements
//exception thrown here
//lines not reached if exception thrown
} catch (Exception e) {
//lines reached only when exception is thrown
} finally {
// always executed when the try block is exited
//independent of an exception thrown or not
}
O bloco finally impedir a execução de...
- Quando chamado
System.exit(0);
- Se uma JVM termina.
- Erros na JVM
Adicionar a @vibhash resposta como nenhuma outra resposta explica o que acontece no caso de um objeto mutável como a abaixo.
public static void main(String[] args) {
System.out.println(test().toString());
}
public static StringBuffer test() {
StringBuffer s = new StringBuffer();
try {
s.append("sb");
return s;
} finally {
s.append("updated ");
}
}
Saída
sbupdated
Eu tentei isso, Ele é único thread.
class Test {
public static void main(String args[]) throws Exception {
Object obj = new Object();
try {
synchronized (obj) {
obj.wait();
System.out.println("after wait()");
}
} catch (Exception e) {
} finally {
System.out.println("finally");
}
}
}
O thread principal será em estado de espera para sempre, daí, finalmente, nunca vai ser chamado,
assim, a saída do console não vai seqüência de impressão: after wait()
ou finally
Concordou com @Stephen C, o exemplo acima é um dos 3º caso mencionar aqui:
A adição de mais alguns, tais loop infinito de possibilidades no código a seguir:
// import java.util.concurrent.Semaphore;
class Test {
public static void main(String[] args) {
try {
// Thread.sleep(Long.MAX_VALUE);
// Thread.currentThread().join();
// new Semaphore(0).acquire();
// while (true){}
System.out.println("after sleep join semaphore exit infinite while loop");
} catch (Exception e) {
} finally {
System.out.println("finally");
}
}
}
Caso 2:Se a JVM falha primeiro
import sun.misc.Unsafe;
import java.lang.reflect.Field;
class Test {
public static void main(String args[]) {
try {
unsafeMethod();
// Runtime.getRuntime().halt(123);
System.out.println("After Jvm Crash!");
} catch (Exception e) {
} finally {
System.out.println("finally");
}
}
private static void unsafeMethod() throws NoSuchFieldException, IllegalAccessException {
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
Unsafe unsafe = (Unsafe) f.get(null);
unsafe.putAddress(0, 0);
}
}
Ref: Como você se falhar uma JVM?
Caso 6:Se, finalmente, o bloco vai ser executado pela thread daemon e todos os outros não-daemon threads saída antes que finalmente é chamado.
class Test {
public static void main(String args[]) {
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
printThreads("Daemon Thread printing");
// just to ensure this thread will live longer than main thread
Thread.sleep(10000);
} catch (Exception e) {
} finally {
System.out.println("finally");
}
}
};
Thread daemonThread = new Thread(runnable);
daemonThread.setDaemon(Boolean.TRUE);
daemonThread.setName("My Daemon Thread");
daemonThread.start();
printThreads("main Thread Printing");
}
private static synchronized void printThreads(String str) {
System.out.println(str);
int threadCount = 0;
Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
for (Thread t : threadSet) {
if (t.getThreadGroup() == Thread.currentThread().getThreadGroup()) {
System.out.println("Thread :" + t + ":" + "state:" + t.getState());
++threadCount;
}
}
System.out.println("Thread count started by Main thread:" + threadCount);
System.out.println("-------------------------------------------------");
}
}
saída:Isso não imprimir "finalmente", que implica "Finalmente" bloco em "linha do daemon" não foi executada
main Thread Printing Thread :Thread[My Daemon Thread,5,main]:state:BLOCKED Thread :Thread[main,5,main]:state:RUNNABLE Thread :Thread[Monitor Ctrl-Break,5,main]:state:RUNNABLE Thread count started by Main thread:3 ------------------------------------------------- Daemon Thread printing Thread :Thread[My Daemon Thread,5,main]:state:RUNNABLE Thread :Thread[Monitor Ctrl-Break,5,main]:state:RUNNABLE Thread count started by Main thread:2 ------------------------------------------------- Process finished with exit code 0