Pergunta

Sintaxe à parte, qual é a diferença entre

try {
}
catch() {
}
finally {
    x = 3;
}

e

try {
}
catch() {
}

x = 3;

editar:no .NET 2.0?


então

try {
    throw something maybe
    x = 3
}
catch (...) {
    x = 3
}

é comportamentalmente equivalente?

Foi útil?

Solução

Depende da linguagem, pois pode haver algumas pequenas diferenças semânticas, mas a ideia é que ela seja executada (quase) sempre, mesmo que o código no bloco try gere uma exceção.

No segundo exemplo, se o código no bloco catch retornar ou sair, x = 3 não será executado.Na primeira vai.

Na plataforma .NET, em alguns casos a execução do bloco final não ocorrerá:Exceções de segurança, suspensões de threads, desligamento do computador :), etc.

Outras dicas

Bem, por um lado, se você RETURN dentro do seu bloco try, o finalmente ainda será executado, mas o código listado abaixo do bloco try-catch-finally não.

Em Java:

Finalmente sempre é chamado, independentemente de a exceção ter sido capturada corretamente em catch(), ou de fato se você tiver alguma captura.

tente pegar finalmente é uma construção muito importante.Você pode ter certeza de que mesmo que uma exceção seja lançada, o código no bloco final será executado.É muito importante lidar com recursos externos para liberá-los.A coleta de lixo não fará isso por você.Na última parte você não deveria ter retornar declarações ou lançar exceções.É possível fazer isso, mas é uma prática ruim e pode levar a resultados imprevisíveis.

Se você tentar este exemplo:

try {
  return 0;
} finally {
  return 2;
}

O resultado será 2 :)

Comparação com outras línguas: Retornar de finalmente

Existem várias coisas que tornam um bloco final útil:

  1. Se você retornar dos blocos try ou catch, o bloco finalmente ainda será executado, logo antes do controle ser devolvido à função de chamada
  2. Se ocorrer uma exceção no bloco catch ou um tipo de exceção não detectada no bloco try, o código no bloco finalmente ainda será executado.

Estes tornam os blocos finalmente excelentes para fechar identificadores de arquivos ou soquetes.

No caso de try e catch estarem vazios, não há diferença.Caso contrário, você pode ter certeza de que finalmente será executado.

Se você, por exemplo, lançar uma nova exceção em seu bloco catch (relançar), a atribuição só será executada se estiver no bloco final.

Normalmente, um finalmente é usado para limpar você mesmo (fechar conexões de banco de dados, identificadores de arquivos e similares).

Você nunca deve usar instruções de controle (return, break, continue) finalmente, pois isso pode ser um pesadelo de manutenção e, portanto, é considerado uma má prática

O bloco final sempre será chamado (bem, na verdade não sempre ...) mesmo se uma exceção for lançada ou uma instrução de retorno for alcançada (embora isso possa depender do idioma).É uma forma de limpeza que você sabe que sempre será chamada.

@iAn e @mats:

Eu não "destruiria" nada em finalmente {} que tenha sido "configurado" no try {} como regra.Seria melhor extrair a criação do stream fora do try {}.Se você precisar lidar com uma exceção na criação do fluxo, isso poderá ser feito em um escopo maior.

StreamReader stream = new StreamReader("foo.bar");  
try {
    mySendSomethingToStream(stream);
}
catch(noSomethingToSendException e) {
    //Swallow this    
    logger.error(e.getMessage());
}
catch(anotherTypeOfException e) {
    //More serious, throw this one back
    throw(e);
}
finally {
    stream.close();  
}

Assim, você pode limpar quaisquer conexões abertas, etc.inicializado no bloco try.Se você abrisse uma conexão e ocorresse uma exceção, essa exceção não seria fechada corretamente.É para esse tipo de cenário que serve o bloco final.

O bloco final deve ser executado independentemente de você ter capturado a exceção ou não.Ver Exemplo de tentar / capturar / finalmente

@Ed, você pode estar pensando em algo como um catch(...) que captura uma exceção não especificada em C++.

Mas finally é um código que será executado independentemente do que acontecer no catch blocos.

A Microsoft tem uma página de ajuda em tente finalmente para C#

O bloco final está no mesmo escopo do try/catch, então você terá acesso a todas as variáveis ​​definidas nele.

Imagine que você tem um manipulador de arquivos, essa é a diferença na forma como ele seria escrito.

try
{
   StreamReader stream = new StreamReader("foo.bar");
   stream.write("foo");
}
catch(Exception e) { } // ignore for now
finally
{
   stream.close();
}

comparado com

StreamReader stream = null;
try
{
    stream = new StreamReader("foo.bar");
    stream.write("foo");
} catch(Exception e) {} // ignore

if (stream != null)
    stream.close();

Lembre-se, porém, de que não há garantia de que qualquer coisa dentro dele funcione.Imagine que você recebe um sinal de aborto, o Windows trava ou falta energia.Depender finalmente de código crítico para os negócios é ruim.

Qualquer código no final é executado mesmo no caso de uma exceção não tratada.Normalmente, o código finalmente é usado para limpar declarações locais de código não gerenciado usando .dispose().

Finalmente, os blocos permitem que você, como desenvolvedor, se organize, independentemente das ações do código anterior no bloco try{}, erros encontrados, e como outros apontaram isso, isso se enquadra principalmente na proteção de liberação de recursos - fechamento ponteiros/soquetes/conjuntos de resultados, retornando conexões para um pool etc.

@mats está certo ao dizer que sempre há potencial para falhas "graves" - finalmente os blocos não devem incluir código de missão crítica, o que sempre deve ser feito transacionalmente dentro do try{}

@mats novamente - A verdadeira beleza é que ele permite que você retire exceções de seus próprios métodos e ainda garanta que você arrumará:

try
{
StreamReader stream = new StreamReader("foo.bar");
mySendSomethingToStream(stream);
}
catch(noSomethingToSendException e) {
    //Swallow this    
    logger.error(e.getMessage());
}
catch(anotherTypeOfException e) {
    //More serious, throw this one back
    throw(e);
}
finally
{
stream.close();
}

Portanto, podemos capturar muitos tipos de exceção, processá-las de maneira diferente (a primeira permite a execução de qualquer coisa além do try{}, a segunda retorna efetivamente), mas sempre esclarecê-las de maneira organizada e organizada.

Em Java, você o usa para qualquer coisa que queira executar, independentemente de ter usado um "return", apenas executado o bloco try ou uma exceção detectada.

Por exemplo, fechar uma sessão de banco de dados ou uma conexão JMS ou desalocar algum recurso do sistema operacional.

Suponho que seja semelhante no .NET?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top