Por que usamos blocos finally?

91

Até onde eu posso dizer, os dois trechos de código a seguir servirão ao mesmo propósito. Por que ter finallyblocos?

Código A:

try { /* Some code */ }
catch { /* Exception handling code */ }
finally { /* Cleanup code */ }

Código B:

try { /* Some code */ }
catch { /* Exception handling code */ }
// Cleanup code
Mohammad Nadeem
fonte
Isso não é específico para C #, é uma questão .Net
Sruly
1
Não é mais necessário com java7: AutomaticResourceManagement, try (new resourceDeclartion ()) {}
Kanagavelu Sugumar

Respostas:

140
  • O que acontece se uma exceção que você não está tratando for lançada? (Espero que você não esteja pegando Throwable...)
  • O que acontece se você retornar de dentro do bloco try?
  • O que acontece se o bloco catch lançar uma exceção?

Um finallybloco garante que não importa como você saia desse bloco (modulo algumas maneiras de abortar todo o processo explicitamente), ele será executado. Isso é importante para a limpeza determinística de recursos.

Jon Skeet
fonte
50
Não é necessariamente verdade; finalmente não será executado se (1) houver uma System.exit()chamada (2) houver um loop infinito na tentativa ou um dos blocos de captura (3) Eu puxo o plugue do computador
NullUserException
2
@Alon tente {return 1; } finalmente {retrun 2; } Você obterá 2
Dennis C de
19
@NullUserException: Conseqüentemente, o bit "módulo de algumas maneiras ..."
Jon Skeet
2
John Skeet mora aqui no stackoverflow, cada pergunta é como uma campainha tocando, ele tem que responder :)
naikus
1
Esta postagem discute as (raras) condições sob as quais NÃO serei chamado.
Candamir
13

Observe que (pelo menos em Java, provavelmente também em C #) também é possível ter um trybloco sem a catch, mas com a finally. Quando ocorre uma exceção no trybloco, o código no finallybloco é executado antes que a exceção seja lançada mais acima:

InputStream in = new FileInputStream("somefile.xyz");
try {
    somethingThatMightThrowAnException();
}
finally {
    // cleanup here
    in.close();
}
Jesper
fonte
7

Você pode querer colocar o código que deseja executar de qualquer maneira, independentemente do que acontece em seu bloco try ou catch.

Além disso, se você estiver usando vários catch e se quiser colocar algum código que seja comum para todos os blocos catch, este seria um lugar para colocar - mas você não pode ter certeza de que todo o código em try foi executado.

Por exemplo:

conn c1 = new connection();
try {
    c1.dosomething();
} catch (ExceptionA exa) {
    handleexA();
    //c1.close();
} catch (ExceptionB exb) {
    handleexB();
    //c1.close();
} finally {
    c1.close();
}
Balaji Natesan
fonte
1
E se eu não usar 'finalmente', mas fechar a conexão?
Istiaque Ahmed
5

Finalmente, sempre é executado, enquanto seu código após a captura não pode.

Sruly
fonte
1
Por que não! Se a exceção for tratada corretamente, o código será executado definitivamente.
Mohammad Nadeem
1
@Nadeem: Veja minha resposta por 3 motivos pelos quais isso pode não acontecer.
Jon Skeet
2

Mesmo que nosso aplicativo seja fechado à força, haverá algumas tarefas, que devemos executar (como liberação de memória, fechamento de banco de dados, bloqueio de liberação, etc), se você escrever essas linhas de código no finallybloco, ele será executado se uma exceção for lançada ou não...

Seu aplicativo pode ser uma coleção de encadeamentos, Exceptionencerra o encadeamento, mas não o aplicativo inteiro, neste caso finallyé mais útil.

Em alguns casos finally, não será executado, como JVM Fail, Thread terminate, etc.

Sandeep P
fonte
1

Porque você precisa desse código para ser executado independentemente de quaisquer exceções que possam ser lançadas. Por exemplo, você pode precisar limpar alguns recursos não gerenciados (a construção 'using' compila para um bloco try / finally).

Ed S.
fonte
1

Ainda rolando para baixo? Aqui está!

Esta questão me deu um tempo difícil atrás.

try
{
 int a=1;
 int b=0;
 int c=a/b;
}
catch(Exception ex)
{
 console.writeline(ex.Message);
}
finally
{
 console.writeline("Finally block");
}
console.writeline("After finally");

o que seria impresso no cenário acima? Sim, adivinhou certo:

  • ex. Mensagem - seja o que for (provavelmente tentativa de divisão por zero)

  • Finalmente bloquear

  • Depois de finalmente

    try
    {
        int a=1;
        int b=0;
        int c=a/b;
    }
    catch(Exception ex)
    {
        throw(ex);
    }
    finally
    {
        console.writeline("Finally block");
    }
    console.writeline("After finally");
    

O que isso imprimiria? Nada! Ele lança um erro, pois o bloco catch gerou um erro.

Em uma boa estrutura de programação, suas exceções seriam afuniladas, no sentido de que esse código seria tratado a partir de outra camada. Para estimular tal caso, vou tentar este código.

try
{    
 try
    {
     int a=1;
     int b=0;
     int c=a/b;
    }
    catch(Exception ex)
    {
     throw(ex);
    }
    finally
    {
     console.writeline("Finally block")
    }
    console.writeline("After finally");
}
catch(Exception ex)
{
 console.writeline(ex.Message);
}

Nesse caso, a saída seria:

  • Finalmente bloquear
  • ex.Message - seja o que for.

É claro que quando você captura uma exceção e a lança novamente em outras camadas (Funilamento), o código após o lançamento não é executado. Ele age de forma semelhante ao funcionamento de um retorno dentro de uma função.

Agora você sabe por que não fechar seus recursos nos códigos após o bloco catch. Coloque-os no bloco finally.

Ashique razak
fonte
0

Pode haver momentos em que você deseja executar um trecho de código, não importa o quê. Se uma exceção é lançada ou não. Então se usa finally.

Igualitário
fonte
0

finally SEMPRE executa, a menos que o JVM tenha sido encerrado, finally apenas fornece um método para colocar o código de limpeza em um só lugar.

Seria muito tedioso se você tivesse que colocar o código de limpeza em cada um dos catchblocos.

Mahmoud Hanafy
fonte
0

Se o bloco catch lançar qualquer exceção, o código restante não será executado, portanto, temos que escrever o bloco final.

Reshma Kore
fonte
0

finalmente o bloco em java pode ser usado para colocar o código de "limpeza", como fechar um arquivo, fechar uma conexão etc.


O bloco finally não será executado se o programa sair (chamando System.exit () ou causando um erro fatal que faz com que o processo seja abortado).

Aakersh Sharma
fonte