Odpowiedzi:
Konstrukcje
try { ... }
catch () { ... } /* You can even omit the () here */
try { ... }
catch (Exception e) { ... }
są podobne pod tym względem, że oba będą przechwytywać każdy wyjątek rzucony wewnątrz try
bloku (i jeśli nie używasz tego po prostu do rejestrowania wyjątków, należy tego unikać ). Teraz spójrz na te:
try { ... }
catch ()
{
/* ... */
throw;
}
try { ... }
catch (Exception e)
{
/* ... */
throw;
}
try { ... }
catch (Exception e)
{
/* ... */
throw e;
}
Pierwszy i drugi blok try-catch są DOKŁADNIE to samo, po prostu ponownie wyrzucają bieżący wyjątek, a ten wyjątek zachowa swoje „źródło” i ślad stosu.
Trzeci blok try-catch jest inny. Kiedy zgłasza wyjątek, zmieni źródło i ślad stosu, tak że będzie wyglądało na to, że wyjątek został wyrzucony z tej metody, z tej samej linii throw e
w metodzie zawierającej ten blok try-catch.
Którego należy użyć? To naprawdę zależy od każdego przypadku.
Załóżmy, że masz Person
klasę z .Save()
metodą, która utrwali ją w bazie danych. Powiedzmy, że Twoja aplikacja Person.Save()
gdzieś wykonuje tę metodę. Jeśli twoja DB odmówi uratowania Osoby, .Save()
wyrzuci wyjątek. Należy użyć throw
czy throw e
w tym przypadku? Cóż, to zależy.
Wolę robić:
try {
/* ... */
person.Save();
}
catch(DBException e) {
throw new InvalidPersonException(
"The person has an invalid state and could not be saved!",
e);
}
Powinno to spowodować umieszczenie wyjątku DBException jako „wewnętrznego wyjątku” zgłaszanego nowszego wyjątku. Tak więc podczas sprawdzania tego InvalidPersonException, ślad stosu będzie zawierał informacje z powrotem do metody Save (może to wystarczyć do rozwiązania problemu), ale nadal masz dostęp do oryginalnego wyjątku, jeśli go potrzebujesz.
Na koniec, gdy spodziewasz się wyjątku, powinieneś naprawdę wychwycić ten jeden konkretny wyjątek, a nie ogólny Exception
, tj. Jeśli spodziewasz się wyjątku InvalidPersonException, powinieneś preferować:
try { ... }
catch (InvalidPersonException e) { ... }
do
try { ... }
catch (Exception e) { ... }
Powodzenia!
Pierwsza zachowuje ślad stosu, a druga resetuje go. Oznacza to, że jeśli użyjesz drugiego podejścia, ślad stosu wyjątku zawsze będzie rozpoczynał się od tej metody i utracisz oryginalny ślad wyjątku, co może być katastrofalne dla kogoś czytającego dzienniki wyjątków, ponieważ nigdy nie dowie się pierwotnej przyczyny wyjątku .
Drugie podejście może być przydatne, gdy chcesz dodać dodatkowe informacje do śladu stosu, ale jest używane w następujący sposób:
try
{
// do something
}
catch (Exception ex)
{
throw new Exception("Additional information...", ex);
}
Jest post na blogu omawiający różnice.
throw
vs throw e
.
Powinieneś użyć
try { }
catch(Exception e)
{ throw }
jeśli chcesz zrobić coś z wyjątkiem przed ponownym wyrzuceniem (na przykład logowanie). Samotny rzut zachowuje ślad stosu.
Różnica między przechwytywaniem bez parametrów a a catch(Exception e)
polega na tym, że otrzymujesz odwołanie do wyjątku. Wyjątki niezarządzane z platformy w wersji 2 są opakowane w wyjątek zarządzany, więc wyjątek bez parametrów nie jest już przydatny do niczego.
Różnica między throw;
i throw e;
polega na tym, że pierwszy jest używany do ponownego zgłaszania wyjątków, a drugi służy do zgłaszania nowo utworzonego wyjątku. Jeśli użyjesz drugiego do ponownego wyrzucenia wyjątku, potraktuje go jak nowy wyjątek i zastąpi wszystkie informacje o stosie z miejsca, w którym został pierwotnie wyrzucony.
Więc nie powinieneś używać żadnej z alternatyw w pytaniu. Nie należy używać przechwytywania bez parametrów, a throw;
do ponownego zgłaszania wyjątku.
Ponadto w większości przypadków należy użyć bardziej szczegółowej klasy wyjątków niż klasa bazowa dla wszystkich wyjątków. Powinieneś łapać tylko te wyjątki, które przewidujesz.
try {
...
} catch (IOException e) {
...
throw;
}
Jeśli chcesz dodać jakiekolwiek informacje podczas ponownego zgłaszania wyjątku, utwórz nowy wyjątek z oryginalnym wyjątkiem jako wyjątek wewnętrzny, aby zachować wszystkie informacje:
try {
...
} catch (IOException e) {
...
throw new ApplicationException("Some informative error message", e);
}