it-swarm-pt.tech

Um bloco final sempre é executado em Java?

Considerando este código, posso ser absolutamente certo que o bloco finally sempre é executado, não importa o que something() seja?

try {  
    something();  
    return success;  
}  
catch (Exception e) {   
    return failure;  
}  
finally {  
    System.out.println("I don't know if this will get printed out");
}
2159
jonny five

Sim, finally será chamado após a execução dos blocos de código try ou catch.

As únicas vezes que finally não serão chamadas são:

  1. Se você invocar System.exit()
  2. Se a JVM falhar primeiro
  3. Se a JVM atingir um loop infinito (ou alguma outra instrução não interromper, não finalizável) no bloco try ou catch
  4. Se o SO forçar o término do processo da JVM; por exemplo, kill -9 <pid> no UNIX
  5. Se o sistema host morrer; por exemplo, falha de energia, erro de hardware, pânico do sistema operacional, etc.
  6. Se o bloco finally for executado por um encadeamento do daemon e todos os outros encadeamentos não-daemon forem encerrados antes de finally ser chamado
2415
jodonnell

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
502
Kevin

Além disso, embora seja uma prática ruim, se houver uma instrução de retorno dentro do bloco finally, ele irá superar qualquer outro retorno do bloco regular. Ou seja, o seguinte bloco retornaria falso:

try { return true; } finally { return false; }

Mesma coisa com lançamentos de exceções do bloco finally.

362
MooBob42

Aqui estão as palavras oficiais da especificação da linguagem Java.

14.20.2. Execução de try-finally e try-catch-finally

Uma instrução try com um bloco finally é executada executando primeiro o bloco try. Então há uma escolha:

  • Se a execução do bloco try for concluída normalmente, [...]
  • Se a execução do bloco try for concluída abruptamente devido a um throw de um valor V, [...]
  • Se a execução do bloco try for concluída abruptamente por qualquer outro motivo R, o bloco finally será executado. Então há uma escolha:
    • Se o bloco finally for concluído normalmente, a instrução try será concluída abruptamente pelo motivo R.
    • Se o bloco finally for completado abruptamente pela razão S, então a instrução try será completada abruptamente pelo motivo S ( e reason R é descartado ).

A especificação para return realmente torna isso explícito:

JLS 14.17 A declaração de retorno

ReturnStatement:
     return Expression(opt) ;

Uma instrução return sem Expression tries para transferir o controle para o invocador do método ou construtor que o contém.

Uma instrução return com um Expression tries para transferir o controle para o invocador do método que o contém; o valor do Expression se torna o valor da invocação do método.

As descrições precedentes dizem " tentativas para transferir controle" em vez de apenas "transferencia de controle" porque se houver alguma instrução try dentro do método ou construtor cujos blocos try contém a instrução return, então qualquer cláusula finally daquelas instruções try será executada, em ordem, do mais interno para o mais externo, antes que o controle seja transferido para o invocador do método ou construtor. A conclusão abrupta de uma cláusula finally pode interromper a transferência de controle iniciada por uma instrução return.

249
polygenelubricants

Além das outras respostas, é importante ressaltar que 'finalmente' tem o direito de sobrescrever qualquer exceção/valor retornado pelo bloco try..catch. 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 o lança:

public static int getMonthsInYear() {
    try {
        return 12;          
    }
    finally {
        throw new RuntimeException();
    }
}
148
Eyal Schneider

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.");
    }
}

As saídas acima do código:

finalmente trunfos retornam.
2

Isso ocorre porque quando return i; é executado, i tem um valor 2. Depois disso, o bloco finally é executado, onde 12 é atribuído a i e, em seguida, System.out out é executado.

Depois de executar o bloco finally, o bloco try retorna 2, em vez de retornar 12, porque esta declaração de retorno não é executada novamente.

Se você depurar este código no Eclipse, você terá a sensação de que depois de executar System.out of finally block, a instrução return do bloco try será executada novamente. Mas este não é o caso. Simplesmente retorna o valor 2.

109
vibhash

Aqui está uma elaboração de a resposta de Kevin . É importante saber que a expressão a ser retornada é avaliada antes de finally, mesmo que seja retornada 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
95
WoodenKitty

Essa é toda a ideia de um bloco final. Ele permite que você faça limpezas que poderiam ser ignoradas, porque você retorna, entre outras coisas, é claro.

Finalmente é chamado independentemente do que acontece no bloco try ( a menos que você chama System.exit(int) ou o Java Virtual Machine inicia por algum outro motivo).

52
Chris Cooper

Uma maneira lógica de pensar sobre isso é:

  1. Código colocado em um bloco final deve ser executado o que ocorrer dentro do bloco try
  2. Então, se o código no bloco try tentar retornar um valor ou lançar uma exceção, o item é colocado 'na prateleira' até que o bloco finally possa ser executado
  3. Como o código no bloco finally tem (por definição) uma alta prioridade, ele pode retornar ou lançar o que quiser. Nesse caso, qualquer coisa deixada "na prateleira" é descartada.
  4. A única exceção a isto é se o VM desliga completamente durante o bloco try, por ex. por 'System.exit'
38
Garth Gilmour

finalmente é sempre executado a menos que haja finalização anormal do programa (como chamar System.exit (0) ..). então, o seu sistema será impresso

18
shyam

Também um retorno em finalmente jogará fora qualquer exceção. http://jamesjava.blogspot.com/2006/03/dont-return-in-finally-clause.html

18
James A. N. Stauffer

O bloco finally é sempre executado, a menos que haja uma finalização anormal do programa, resultante de uma falha da JVM ou de uma chamada para System.exit(0).

Além disso, qualquer valor retornado de dentro do bloco finally substituirá o valor retornado antes da execução do bloco finally, portanto, tenha cuidado ao verificar todos os pontos de saída ao usar o try finally.

17
user9189

Não, nem sempre um caso de exceção é // System.exit (0); antes do bloco finally impede que finalmente seja 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");
        }
    }
}
17
Rajendra Jadi

Finalmente é sempre executado que é o ponto inteiro, só porque aparece no código após o retorno não significa que é assim que é implementado. O Java Runtime tem a responsabilidade de executar esse código ao sair do bloco try.

Por exemplo, se você tem o seguinte:

int foo() { 
    try {
        return 42;
    }
    finally {
        System.out.println("done");
    }
}

O tempo de execução irá gerar algo assim:

int foo() {
    int ret = 42;
    System.out.println("done");
    return 42;
}

Se uma exceção não identificada for lançada, o bloco finally será executado e a exceção continuará sendo propagada.

12
Motti

Isso é porque você atribuiu o valor de i como 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;
    }
}
10
Wasim

Porque um bloco finally sempre será chamado a menos que você chame System.exit() (ou o encadeamento trava).

9
Jay Riggs

A resposta é simplesYES.

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
9
Meet

Sim, será chamado. Esse é o objetivo de ter finalmente uma palavra-chave. Se saltar do bloco try/catch poderia simplesmente pular o bloco finally, seria o mesmo que colocar o System.out.println fora do try/catch.

8
Mendelt

Sim, finalmente o bloco é sempre executado. A maioria do desenvolvedor usa esse bloco para fechar a conexão com o banco de dados, objeto do conjunto de resultados, objeto de instrução e também usa o Java hibernate para reverter a transação.

8
Gautam Viradiya

Concisamente, na documentação oficial de Java (Clique em aqui ), está escrito que -

Se a JVM sair enquanto o código try ou catch estiver sendo executado, o bloco finally poderá não ser executado. Da mesma forma, se o thread que está executando o código try ou catch for interrompido ou interrompido, o bloco finally poderá não ser executado, mesmo que o aplicativo como um todo continue.

8
bikz05

Sim vai. Apenas o caso não será saídas da JVM ou falhas

7
abhig

Sim vai. Não importa o que aconteça no seu bloco try ou catch, a menos que System.exit () seja chamado ou a JVM caia. se houver qualquer declaração de retorno no (s) bloco (s), finalmente será executada antes da declaração de retorno.

7
Karthikeyan

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");
        }
    }
}

A partir do Java 1.8.162, o bloco de código acima fornece a seguinte saída:

-abc-
---AGAIN---
-abc-xyz-abc-
---PRINT THE RESULT---
-abc-xyz-abc-xyz

isso significa que usar 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.
    }
}
7
Samim

Eu tentei isso, é single threaded.

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 estará no estado de espera para sempre, portanto, finalmente, nunca será chamado,

então a saída do console não irá imprimir string: after wait() ou finally

Concordado com @Stephen C, o exemplo acima é um dos três casos mencionados aqui :

Adicionando mais algumas possibilidades de loop infinito no seguinte código:

// 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ê falha uma JVM?

Caso 6: Se finalmente o bloco for executado pelo daemon thread e todos os outros threads não daemon forem encerrados antes de finalmente ser 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("-------------------------------------------------");
    }
}

output: Isto não imprime "finally" o que implica que "Finally block" no "daemon thread" não foi executado

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
6
dkb

Sim, porque nenhuma instrução de controle pode impedir que finally seja executada.

Aqui está um exemplo de referência, onde todos os blocos de código serão executados:

| 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, acompanham 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
    }
}
6
Dávid Horváth

finally será executado e com certeza.

finally não será executado nos casos abaixo:

caso 1 :

Quando você está executando System.exit().

caso 2:

Quando seu JVM/Thread falha.

caso 3:

Quando sua execução é interrompida no meio manualmente.

6
Utkash Bhatt

try- catch- finally são as palavras-chave para usar o caso de tratamento de exceções.
Como explicação explanatória

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 impede a execução ...

  • Quando você ligou System.exit(0);
  • Se o JVM sair.
  • Erros na JVM
6
Poorna Senani Gamage

Se você não manipular a exceção, antes de encerrar o programa, a JVM será finalmente bloqueada. Ele não será executado somente se a execução normal do programa falhar no término do programa devido aos seguintes motivos:.

  1. Por causar um erro fatal que faz com que o processo seja anulado.

  2. Rescisão do programa devido a memória corrompida.

  3. Chamando System.exit ()

  4. Se o programa entrar em loop infinito.

6
Vikas Suryawanshi

Isso é realmente verdade em qualquer idioma ... finalmente será sempre executado antes de uma instrução de retorno, não importa onde esse retorno esteja no corpo do método. Se não fosse esse o caso, o bloco final não teria muito significado.

6
Scott Dorman

Adicionando a resposta de @ vibhash como nenhuma outra resposta explica o que acontece no caso de um objeto mutável como o 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 
6
Pradeep Kumaresan

Sim, está escrito aqui

Se a JVM sair enquanto o código try ou catch estiver sendo executado, o bloco finally poderá não ser executado. Da mesma forma, se o thread que está executando o código try ou catch for interrompido ou interrompido, o bloco finally poderá não ser executado, mesmo que o aplicativo como um todo continue.

5
Danail Tsvetanov

Além do ponto sobre o retorno em finalmente substituir um retorno no bloco try, o mesmo vale para uma exceção. Um bloco finally que lança uma exceção substituirá um retorno ou uma exceção lançada de dentro do bloco try.

5
Alex Miller

NEM SEMPRE

A especificação da Linguagem Java descreve como os blocos try-catch-finally e try-catch funcionam em 14.20.2
Em nenhum lugar especifica que o bloco finally é sempre executado. Mas para todos os casos em que os blocos try-catch-finally e try-finally completam, ele especifica que antes da conclusão ser finalmente executada.

try {
  CODE inside the try block
}
finally {
  FIN code inside finally block
}
NEXT code executed after the try-finally block (may be in a different method).

O JLS não garante queFINseja executado apósCODE. O JLS garante que seC&OACUTE;DIGOePR&OACUTE;XIMOsão executados entãoFINsempre será executado apósC&OACUTE;DIGOe antes deNEXT.

Por que o JLS não garante que o bloco finally seja sempre executado após o bloco try? Porque isso é impossível. É improvável, mas possível, que a JVM seja abortada (kill, crash, power off) logo após a conclusão do bloco try, mas antes da execução do bloco finally. Não há nada que o JLS possa fazer para evitar isso.

Assim, qualquer software que por seu próprio comportamento dependa de blocos finalmente executados, sempre que os seus blocos try estiverem completos, são escutados.

Retorna no bloco try são irrelevantes para este problema. Se a execução atingir o código após o try-catch-finally, é garantido que o bloco finally terá sido executado antes, com ou sem devoluções dentro do bloco try.

5
Jose Antonio Dura Olmos

O bloco finally não será chamado após o retorno em alguns cenários exclusivos: se System.exit () for chamado primeiro ou se a JVM falhar.

Deixe-me tentar responder a sua pergunta da maneira mais fácil possível.

Regra 1 : O bloco finally sempre funciona (Embora existam exceções. Mas vamos manter isso por algum tempo.)

Regra 2 : as instruções no bloco finally são executadas quando o controle deixa um try ou um bloco catch. A transferência de controle pode ocorrer como resultado da execução normal, da execução de um break, continue, goto ou a declaração de retorno, ou de uma propagação de uma exceção.

No caso de uma declaração de retorno especificamente (desde a sua legenda), o controle tem que deixar o método de chamada e, portanto, chama o bloco finally da estrutura try-finally correspondente. A instrução de retorno é executada após o bloco finally.

No caso de haver uma instrução de retorno no bloco finally também, ela substituirá definitivamente a que está pendente no bloco try, já que está limpando a pilha de chamadas.

Você pode consultar uma explicação melhor aqui: http://msdn.Microsoft.com/en-us/ .... o conceito é basicamente o mesmo em todos os idiomas de alto nível.

5
Sandip Solanki
  1. Finalmente, o bloco sempre é executado. A menos que e até que System.exit () instrução exista lá (primeira declaração no bloco finally).
  2. Se system.exit () é a primeira instrução, então, finalmente, o bloco não será executado e o controle sairá do bloco finally. Sempre que a instrução System.exit () entra finalmente em bloco até que a instrução finalmente seja executada e quando System.exit () aparece, a força de controle sai completamente do bloco finally.
5
Avinash Pande

O mesmo com o seguinte código:

static int f() {
    while (true) {
        try {
            return 1;
        } finally {
            break;
        }
    }
    return 2;
}

f retornará 2!

4
dibo

Porque o final é sempre chamado em todos os casos que você tem. Você não tem exceção, ainda é chamado, pegue exceção, ainda é chamado

4
vodkhang

Sim, ele sempre será chamado, mas em uma situação ele não chama quando você usa System.exit ()

try{
//risky code
}catch(Exception e){
//exception handling code
}
finally(){
//It always execute but before this block if there is any statement like System.exit(0); then this block not execute.
}
4
Akash Manngroliya

Finalmente, o bloco sempre executa se o manipulador de exceção ou não. Se alguma exceção ocorreu antes de tentar o bloco, então, finalmente, o bloco não será executado.

4
Rohit Chugh

Se uma exceção for lançada, finalmente será executada. Se uma exceção não for lançada, finalmente será executada. Se a exceção for capturada, finalmente será executada. Se a exceção não for capturada, finalmente será executada.

Apenas o tempo que não é executado é quando o JVM sai.

4
Bhushan

Considere isto em um curso normal de execução (isto é, sem qualquer Exceção sendo lançada): se o método não for 'void' então sempre explicitamente retorna alguma coisa, mas, finalmente, sempre é executado

4
Gala101

Tente este código, você entenderá que o código em finally block é executado após a declaração de retorno .

public class TestTryCatchFinally {
    static int x = 0;

    public static void main(String[] args){
        System.out.println(f1() );
        System.out.println(f2() );
    }

    public static int f1(){
        try{
            x = 1;
            return x;
        }finally{
            x = 2;
        }
    }

    public static int f2(){
        return x;
    }
}
4
eric2323223

Fiquei muito confuso com todas as respostas fornecidas em fóruns diferentes e decidi finalmente codificar e ver. A saída é:

finalmente será executado mesmo se houver retorno no bloco try e catch.

try {  
  System.out.println("try"); 
  return;
  //int  i =5/0;
  //System.exit(0 ) ;
} catch (Exception e) {   
  System.out.println("catch");
  return;
  //int  i =5/0;
  //System.exit(0 ) ;
} finally {  
   System.out.println("Print me FINALLY");
}

Saída

experimentar

Imprima-me FINALMENTE

  1. Se o retorno for substituído por System.exit(0), tente capturar o bloco no código acima e uma exceção ocorrerá antes dele, por qualquer motivo.
4
milton

finalmente também pode ser encerrado prematuramente se uma exceção for lançada dentro de um bloco finally aninhado. O compilador irá avisá-lo que o bloco finally não completa normalmente ou dá um erro que você tem código inacessível. O erro para código inacessível será mostrado apenas se o lançamento não estiver por trás de uma instrução condicional ou dentro de um loop.

try{
}finally{
   try{
   }finally{
      //if(someCondition) --> no error because of unreachable code
      throw new RunTimeException();
   }
   int a = 5;//unreachable code
}
3
HopefullyHelpful

Finalmente é sempre chamado no final

quando você tenta, ele executa algum código, se algo acontecer em try, então catch irá capturar aquela exceção e você pode imprimir alguns mssg ou lançar um erro, então finalmente o bloco é executado.

Finalmente é normalmente usado ao fazer limpezas, por exemplo, se você usar um scanner em Java, você provavelmente deve fechar o scanner, pois leva a outros problemas, como não ser capaz de abrir algum arquivo

2
Rubin Luitel

finalmente o bloco é executado sempre, mesmo se você colocar uma declaração de retorno no bloco try. O bloco finally será executado antes da declaração de retorno.

2
Sabrina