Faz sentido fazer "tentar finalmente" sem "pegar"?

127

Eu vi um código como este:

    try
    {
        db.store(mydata);
    }
    finally
    {
        db.cleanup();
    }

Eu pensei que trydeveria ter um catch?

Por que esse código faz dessa maneira?

Glanden
fonte
1
Ele garante limpeza como outras respostas mencionado, especialmente para identificadores de arquivo fopenou conexão DB (também em PHP)
MediaVince

Respostas:

182

Isso é útil se você deseja que o método atualmente em execução ainda lance a exceção enquanto permite que os recursos sejam limpos adequadamente. Abaixo está um exemplo concreto de como lidar com a exceção de um método de chamada.

public void yourOtherMethod() {
    try {
        yourMethod();
    } catch (YourException ex) {
        // handle exception
    }
}    

public void yourMethod() throws YourException {
    try {
        db.store(mydata);
    } finally {
        db.cleanup();
    }
}
Taylor Leese
fonte
17
comumente usado com bloqueios como em: lock.lock (); tente {/ * locked * /} finalmente {lock.unlock ()}
minutos
O que acontece se uma exceção for lançada finalmente?
30919 barth
1
@barth Quando não houver nenhum catchbloco, a exceção lançada finallyserá executada antes de qualquer exceção no trybloco. Portanto, se houver duas exceções, uma trye uma, finallya única exceção que será lançada, será a única finally. Esse comportamento não é o mesmo no PHP e no Python, pois as duas exceções serão lançadas ao mesmo tempo nessas linguagens e a ordem das exceções é tryprimeiro e depois finally.
Rain
72

Está lá porque o programador queria ter certeza de que db.cleanup()é chamado mesmo se o código dentro do bloco try lançar uma exceção. Quaisquer exceções não serão tratadas por esse bloco, mas somente serão propagadas para cima após a execução do bloco final.

Matti Virkkunen
fonte
23
+1 Exatamente. O tryestá lá apenas para permitir o finally. Exceções não são capturadas.
Zockman
2
+1 para deixar claro que a exceção continua na pilha até ser capturada. Obrigado
Code Jockey
20

Por que esse código faz dessa maneira?

Porque, aparentemente, o código não sabe como lidar com exceções nesse nível. Tudo bem - desde que um dos chamadores o faça, ou seja, desde que a exceção seja finalmente tratada em algum lugar.

Freqüentemente, o código de baixo nível não pode reagir adequadamente às exceções porque o usuário precisa ser notificado ou a exceção deve ser registrada ou outra estratégia deve ser tentada. O código de baixo nível executa apenas uma função e não sabe sobre tomada de decisão de nível superior.

Mas o código ainda precisa limpar seus recursos (porque, caso contrário, eles vazariam), é o que faz exatamente isso na finallycláusula, certificando-se de que sempre aconteça, independentemente de uma exceção ser lançada ou não.

Konrad Rudolph
fonte
2

O bloco final garante que, mesmo quando uma RuntimeException for lançada (talvez devido a algum bug no código chamado), a db.cleanup()chamada seja feita.

Isso também é frequentemente usado para evitar muitos aninhamentos:

try
{
    if (foo) return false;
    //bla ...
    return true;
}
finally
{
    //clean up
}

Especialmente quando há muitos pontos em que o método retorna, isso melhora a legibilidade, pois qualquer pessoa pode ver que o código de limpeza é chamado em todos os casos.

FRotthowe
fonte
0

O código está fazendo isso para garantir que o banco de dados esteja fechado.
Normalmente, a maneira como você faria isso é colocar todo o código de acesso ao banco de dados no bloco try e, em seguida, fazer uma chamada para fechar o banco de dados no bloco final.
A maneira como try ... finalmente funciona significa que o código no bloco try é executado, e o código no bloco finally é executado quando isso termina ... não importa o quê.
A menos que o computador seja puxado da parede, o finalmente será executado.
Isso significa que, mesmo que uma exceção seja chamada e o método demore três anos para ser executado, ele continuará no bloco final e o banco de dados será fechado.

chustar
fonte
0

Se algum código no bloco try puder gerar uma exceção verificada, ele deverá aparecer na cláusula throws da assinatura do método. Se uma exceção não verificada for lançada, ela será excluída do método.

O bloco final é sempre executado, independentemente de uma exceção ser lançada ou não.

VASO FINO
fonte