Der Unterschied zwischen try / catch / throw und try / catch (e) / throw e

103

Was ist der Unterschied zwischen

try { }
catch
{ throw; }

und

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

?

Und wann soll ich den einen oder anderen benutzen?

Karim
quelle

Antworten:

151

Die Konstruktionen

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

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

sind insofern ähnlich, als beide jede im tryBlock ausgelöste Ausnahme abfangen (und sollten vermieden werden , es sei denn, Sie verwenden dies einfach zum Protokollieren der Ausnahmen ). Schauen Sie sich nun diese an:

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

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

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

Der erste und der zweite Try-Catch-Block sind genau dasselbe, sie lösen einfach die aktuelle Ausnahme erneut aus, und diese Ausnahme behält ihre "Quelle" und die Stapelverfolgung bei.

Der dritte Try-Catch-Block ist anders. Wenn die Ausnahme ausgelöst wird, werden die Quelle und die Stapelverfolgung geändert, sodass der Eindruck entsteht, dass die Ausnahme von dieser Methode aus genau dieser Zeile throw ein der Methode ausgelöst wurde, die diesen Try-Catch-Block enthält.

Welches solltest du verwenden? Es kommt wirklich auf jeden Fall an.

Angenommen, Sie haben eine PersonKlasse mit einer .Save()Methode, die sie in einer Datenbank beibehält. Angenommen, Ihre Anwendung führt die Person.Save()Methode irgendwo aus. Wenn sich Ihre Datenbank weigert, die Person zu speichern, .Save()wird eine Ausnahme ausgelöst. Solltest du throwoder throw ein diesem Fall verwenden? Es hängt davon ab.

Was ich am liebsten mache:

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

Dies sollte die DBException als "innere Ausnahme" der neueren Ausnahme setzen, die ausgelöst wird. Wenn Sie diese InvalidPersonException untersuchen, enthält der Stack-Trace Informationen zur Save-Methode (die möglicherweise ausreicht, um das Problem zu lösen). Sie haben jedoch weiterhin Zugriff auf die ursprüngliche Ausnahme, wenn Sie diese benötigen.

Als letzte Bemerkung, wenn Sie eine Ausnahme erwarten , sollten Sie diese eine bestimmte Ausnahme und nicht eine allgemeine Ausnahme wirklich abfangen Exception, dh wenn Sie eine InvalidPersonException erwarten, sollten Sie Folgendes bevorzugen:

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

zu

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

Viel Glück!

Bruno Reis
quelle
34

Der erste behält die Stapelverfolgung bei, während der zweite sie zurücksetzt. Dies bedeutet, dass bei Verwendung des zweiten Ansatzes die Stapelverfolgung der Ausnahme immer von dieser Methode ausgeht und Sie die ursprüngliche Ausnahmeverfolgung verlieren, was für jemanden, der Ausnahmeprotokolle liest, katastrophal sein kann, da er die ursprüngliche Ursache der Ausnahme nie herausfindet .

Der zweite Ansatz kann nützlich sein, wenn Sie dem Stack-Trace zusätzliche Informationen hinzufügen möchten, er wird jedoch folgendermaßen verwendet:

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

Es gibt einen Blog- Beitrag , in dem die Unterschiede diskutiert werden.

Darin Dimitrov
quelle
Das ist großartig zu wissen!
Myles
Warum also die zweite verwenden? ist es besser, nur den ersten zu verwenden?
Karim
1
Der zweite ist nützlich, wenn Sie nach bestimmten Ausnahmen suchen müssen - OutOfRangeException kommt in den Sinn - oder die Nachricht protokollieren müssen usw. Der erste scheint ein Wildcard-Ausnahmebehandler zu sein, der dem Versuch {} catch (...) {} ähnelt in c ++.
3Dave
1
David, das gilt nur für den Fangteil (Ausnahme e) . Und das ist getrennt von throwvs throw e.
Henk Holterman
6

Du solltest benutzen

try { }
catch(Exception e)
{ throw }

Wenn Sie etwas mit der Ausnahme tun möchten, bevor Sie sie erneut auslösen (z. B. Protokollierung). Der einsame Wurf bewahrt die Stapelspur.

Otávio Décio
quelle
und was passiert, wenn ich den "Wurf" hier durch einen "Wurf e" ersetze?
Karim
5

Der Unterschied zwischen einem parameterlosen Fang und einem catch(Exception e)besteht darin, dass Sie einen Verweis auf die Ausnahme erhalten. Ab Framework Version 2 werden nicht verwaltete Ausnahmen in eine verwaltete Ausnahme eingeschlossen, sodass die parameterlose Ausnahme für nichts mehr nützlich ist.

Der Unterschied zwischen throw;und throw e;besteht darin, dass die erste zum erneuten Auslösen von Ausnahmen und die zweite zum Auslösen einer neu erstellten Ausnahme verwendet wird. Wenn Sie die zweite verwenden, um eine Ausnahme erneut auszulösen, wird sie wie eine neue Ausnahme behandelt und alle Stapelinformationen ersetzt, von denen sie ursprünglich ausgelöst wurden.

Sie sollten also keine der Alternativen in der Frage verwenden. Sie sollten den parameterlosen catch nicht verwenden und throw;eine Ausnahme erneut auslösen.

In den meisten Fällen sollten Sie für alle Ausnahmen eine spezifischere Ausnahmeklasse als die Basisklasse verwenden. Sie sollten nur die Ausnahmen abfangen, die Sie erwarten.

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

Wenn Sie beim erneuten Auslösen der Ausnahme Informationen hinzufügen möchten, erstellen Sie eine neue Ausnahme mit der ursprünglichen Ausnahme als innere Ausnahme, um alle Informationen zu erhalten:

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