A diferença entre try / catch / throw e try / catch (e) / throw e

Qual é a diferença entre

try { } catch { throw; } 

e

 try { } catch(Exception e) { throw e;} 

?

E quando devo usar um ou outro?

As construções

 try { ... } catch () { ... } /* You can even omit the () here */ try { ... } catch (Exception e) { ... } 

são semelhantes em que ambos irão capturar todas as exceções lançadas dentro do bloco try (e, a menos que você esteja simplesmente usando isto para registrar as exceções, deve ser evitado ). Agora olhe para estes:

 try { ... } catch () { /* ... */ throw; } try { ... } catch (Exception e) { /* ... */ throw; } try { ... } catch (Exception e) { /* ... */ throw e; } 

O primeiro e o segundo bloco try-catch são EXATAMENTE a mesma coisa, eles simplesmente relançam a exceção atual, e essa exceção manterá sua “origem” e o rastreio da pilha.

O terceiro bloco try-catch é diferente. Quando ele lança a exceção, ele alterará a origem e o rastreio da pilha, de modo que pareça que a exceção foi lançada desse método, daquele throw e linha throw e do método que contém esse bloco try-catch.

Qual deles você deve usar? Isso realmente depende de cada caso.

Digamos que você tenha uma class Person com um método .Save() que a manterá em um database. Digamos que seu aplicativo execute o método Person.Save() algum lugar. Se o seu database se recusar a salvar a Pessoa, então .Save() lançará uma exceção. Você deve usar throw ou throw e neste caso? Bem, isto depende.

O que eu prefiro está fazendo:

 try { /* ... */ person.Save(); } catch(DBException e) { throw new InvalidPersonException( "The person has an invalid state and could not be saved!", e); } 

Isso deve colocar o DBException como a “Exceção Interna” da exceção mais recente sendo lançada. Portanto, quando você inspecionar essa InvalidPersonException, o rastreamento de pilha conterá informações de volta ao método Save (que podem ser suficientes para resolver o problema), mas você ainda terá access à exceção original se precisar.

Como uma observação final, quando você está esperando uma exceção, você deve realmente pegar essa exceção específica, e não uma Exception geral, ou seja, se você está esperando uma InvalidPersonException você deve preferir:

 try { ... } catch (InvalidPersonException e) { ... } 

para

 try { ... } catch (Exception e) { ... } 

Boa sorte!

O primeiro preserva o rastreamento de pilha enquanto o segundo o redefine. Isso significa que, se você usar a segunda abordagem, o rastreamento de pilha da exceção sempre será iniciado a partir desse método e você perderá o rastreio de exceção original que pode ser desastroso para alguém que esteja lendo logs de exceção, pois ele nunca descobrirá a causa original da exceção .

A segunda abordagem pode ser útil quando você deseja adicionar informações adicionais ao rastreamento de pilha, mas ela é usada assim:

 try { // do something } catch (Exception ex) { throw new Exception("Additional information...", ex); } 

Há um post no blog discutindo as diferenças.

Você deveria usar

 try { } catch(Exception e) { throw } 

se você quiser fazer alguma coisa com a exceção antes de re-lançá-lo (log, por exemplo). O lance solitário preserva o rastreamento de pilha.

A diferença entre uma captura sem parâmetros e uma catch(Exception e) é que você obtém uma referência à exceção. As exceções não gerenciadas da versão 2 do framework são agrupadas em uma exceção gerenciada, portanto, a exceção sem parâmetros não é mais útil para nada.

A diferença entre throw; e throw e; é que o primeiro é usado para reexibir exceções e o segundo é usado para lançar uma exceção recém-criada. Se você usar o segundo para relançar uma exceção, ele tratará como uma nova exceção e replaceá todas as informações da pilha de onde foi originalmente lançada.

Então, você não deve usar nenhuma das alternativas na questão. Você não deve usar o catch sem parâmetros, e você deve usar throw; para relançar uma exceção.

Além disso, na maioria dos casos, você deve usar uma class de exceção mais específica que a class base para todas as exceções. Você só deve pegar as exceções que você antecipa.

 try { ... } catch (IOException e) { ... throw; } 

Se você quiser adicionar alguma informação ao relançar a exceção, crie uma nova exceção com a exceção original como uma exceção interna para preservar todas as informações:

 try { ... } catch (IOException e) { ... throw new ApplicationException("Some informative error message", e); }