Respostas:
As construções
try { ... }
catch () { ... } /* You can even omit the () here */
try { ... }
catch (Exception e) { ... }
são semelhantes no sentido de que ambos capturarão todas as exceções lançadas dentro do try
bloco (e, a menos que você esteja simplesmente usando isso para registrar as exceções, devem ser evitados ). Agora olhe para estes:
try { ... }
catch ()
{
/* ... */
throw;
}
try { ... }
catch (Exception e)
{
/* ... */
throw;
}
try { ... }
catch (Exception e)
{
/* ... */
throw e;
}
O primeiro e o segundo blocos 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 rastreamento de pilha.
O terceiro bloco try-catch é diferente. Ao lançar a exceção, ele mudará a origem e o rastreamento de pilha, de modo que pareça que a exceção foi lançada a partir desse método, daquela mesma linha throw e
no método que contém aquele bloco try-catch.
Qual você deve usar? Depende muito de cada caso.
Digamos que você tenha uma Person
classe com um .Save()
método que o manterá em um banco de dados. Digamos que seu aplicativo execute o Person.Save()
método em algum lugar. Se seu banco de dados se recusar a salvar a pessoa, .Save()
lançará uma exceção. Você deve usar throw
ou throw e
neste caso? Bem, isto depende.
O que eu prefiro é fazer:
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, ao inspecionar esta InvalidPersonException, o rastreamento da pilha conterá informações de volta ao método Save (que pode ser suficiente para resolver o problema), mas você ainda terá acesso à exceção original se precisar.
Como uma observação final, quando você está esperando uma exceção, você realmente deve capturar essa exceção específica, e não uma geral Exception
, 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 da pilha, enquanto o segundo o redefine. Isso significa que se você usar a segunda abordagem o rastreamento de pilha da exceção sempre começará a partir deste método e você perderá o rastreamento de exceção original, o que pode ser desastroso para alguém que lê os 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 é usada assim:
try
{
// do something
}
catch (Exception ex)
{
throw new Exception("Additional information...", ex);
}
Há uma postagem no blog discutindo as diferenças.
throw
vs throw e
.
Você deveria usar
try { }
catch(Exception e)
{ throw }
se você quiser fazer algo com a exceção antes de lançá-la novamente (log, por exemplo). O lançamento solitário preserva o rastreamento da pilha.
A diferença entre um catch sem parâmetros e um catch(Exception e)
é que você obtém uma referência para a exceção. A partir da versão 2 do framework, as exceções não gerenciadas 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 relançar 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 a tratará como uma nova exceção e substituirá todas as informações da pilha de onde foi originalmente lançada.
Portanto, você não deve usar nenhuma das alternativas na pergunta. Você não deve usar o catch sem parâmetros e deve usar throw;
para relançar uma exceção.
Além disso, na maioria dos casos, você deve usar uma classe de exceção mais específica do que a classe base para todas as exceções. Você só deve capturar as exceções que prevê.
try {
...
} catch (IOException e) {
...
throw;
}
Se você quiser adicionar qualquer 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);
}