web-dev-qa-db-fra.com

La différence entre try / catch / throw et try / catch (e) / throw e

Quelle est la différence entre

try { }
catch
{ throw; }

et

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

?

Et quand devrais-je utiliser l'un ou l'autre?

99
Karim

Les constructions

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

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

sont similaires en ce sens que les deux intercepteront tous une exception jetée à l'intérieur du bloc try (et, à moins que vous ne l'utilisiez simplement pour enregistrer les exceptions, devrait être évitée ). Maintenant, regardez ces:

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

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

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

Les premier et deuxième blocs try-catch sont EXACTEMENT la même chose, ils renvoient simplement l'exception en cours, et cette exception conservera sa "source" et la trace de la pile.

Le troisième bloc try-catch est différent. Lorsqu'il lève l'exception, il modifie la source et la trace de pile, de sorte qu'il apparaisse que l'exception a été levée par cette méthode, à partir de la même ligne throw e Sur la méthode contenant ce bloc try-catch .

Lequel devriez-vous utiliser? Cela dépend vraiment de chaque cas.

Supposons que vous avez une classe Person avec une méthode .Save() qui la conservera dans une base de données. Supposons que votre application exécute la méthode Person.Save() quelque part. Si votre base de données refuse de sauvegarder la personne, alors .Save() lève une exception. Devez-vous utiliser throw ou throw e Dans ce cas? En fait ça dépend.

Ce que je préfère, c'est faire:

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

Cela devrait placer DBException comme "exception interne" de la plus récente exception levée. Ainsi, lorsque vous inspectez cette exception InvalidPersonException, la trace de la pile contiendra des informations dans la méthode Save (cela pourrait vous suffire pour résoudre le problème), mais vous avez toujours accès à l'exception d'origine si vous en avez besoin.

En guise de remarque finale, lorsque vous attendez une exception , vous devriez vraiment intercepter cette exception spécifique et non une exception générale Exception, Autrement dit, si vous attendez une exception InvalidPersonException, vous devriez préférer:

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

à

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

Bonne chance!

144
Bruno Reis

Le premier conserve la trace de la pile tandis que le second le réinitialise. Cela signifie que si vous utilisez la deuxième approche, la trace de pile de l'exception démarrera toujours à partir de cette méthode et vous perdrez la trace d'exception d'origine, ce qui pourrait être désastreux pour quelqu'un qui lit les journaux des exceptions car il ne saura jamais la cause initiale de l'exception. .

La deuxième approche peut être utile lorsque vous souhaitez ajouter des informations supplémentaires à la trace de pile, mais elle est utilisée comme ceci:

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

Il y a un blog post discutant des différences.

32
Darin Dimitrov

Tu devrais utiliser

try { }
catch(Exception e)
{ throw }

si vous voulez faire quelque chose avec l'exception avant de le relancer (en vous connectant par exemple). Le lancer solitaire préserve la trace de la pile.

6
Otávio Décio

La différence entre une capture sans paramètre et une catch(Exception e) est que vous obtenez une référence à l'exception. Depuis la version 2 du framework, les exceptions non gérées sont encapsulées dans une exception gérée, de sorte que l'exception sans paramètre n'est plus utile pour rien.

La différence entre throw; et throw e; est que le premier est utilisé pour modifier les exceptions et le second pour générer une exception nouvellement créée. Si vous utilisez le second pour renvoyer une exception, il la traitera comme une nouvelle exception et remplacera toutes les informations de pile à partir desquelles elle a été initialement lancée.

Donc, vous ne devriez utiliser aucune des alternatives de la question. Vous ne devriez pas utiliser la capture sans paramètre, et vous devriez utiliser throw; pour relancer une exception.

En outre, dans la plupart des cas, vous devez utiliser une classe d'exception plus spécifique que la classe de base pour toutes les exceptions. Vous ne devez intercepter que les exceptions que vous prévoyez.

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

Si vous souhaitez ajouter des informations lors du renvoi de l'exception, vous créez une nouvelle exception avec l'exception d'origine en tant qu'exception interne afin de préserver toutes les informations:

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