Pourquoi la capture est-elle presque toujours une mauvaise idée?

Pourquoi la catch(Exception) presque toujours une mauvaise idée?

Parce que lorsque vous attrapez une exception, vous êtes censé le gérer correctement . Et vous ne pouvez pas vous attendre à gérer toutes sortes d’exceptions dans votre code. De même, lorsque vous attrapez toutes les exceptions, vous pouvez obtenir une exception qui ne peut pas traiter et empêcher le code supérieur de la stack de le gérer correctement.

Le principe général est de saisir le type le plus spécifique possible.

Petite histoire: c’est ce qu’on appelle le masquage de bogue. Si vous avez un morceau de code qui ne fonctionne pas bien et qui émet des exceptions (ou si vous transmettez des entrées mal formées à ce morceau de code) et que vous observez toutes les exceptions possibles, vous ne découvrirez jamais le bogue et le corrigerez.

Vous ne devriez attraper des exceptions que si vous pouvez les gérer correctement. Comme vous ne pouvez pas gérer correctement toutes les exceptions possibles, vous ne devriez pas les attraper 🙂

Parce que vous ne savez pas vraiment pourquoi une exception est survenue, et que plusieurs exceptions nécessitent une gestion très spécifique de la voiture (si possible), comme une exception OutOfMemoryException et des exceptions système similaires de bas niveau.

Par conséquent, vous ne devez attraper que des exceptions:

  • dont vous savez exactement comment y faire face (par exemple, FileNotFoundException)
  • lorsque vous les relancerez ensuite (par exemple pour effectuer un nettoyage après échec)
  • lorsque vous devez transporter l’exception à un autre thread

Cela dépend de ce dont vous avez besoin. Si vous devez gérer différents types d’exceptions de différentes manières, vous devez utiliser plusieurs blocs catch et intercepter autant d’exceptions spécifiques que possible.

Mais parfois, vous devrez peut-être gérer toutes les exceptions de la même manière. Dans de tels cas, la capture (Exception) peut convenir. Par exemple:

  try { DoSomething(); } catch (Exception e) { LogError(e); ShowErrorMessage(e); // Show "unexpected error ocurred" error message for user. } 

Cela peut être spécifique à Java:

Parfois, vous devrez appeler des méthodes qui lancent des exceptions vérifiées. Si cela se trouve dans votre couche logique EJB / Business, vous avez 2 choix: attrapez-les ou relancez-les.

Attraper des classes d’exceptions spécifiques signifie que vous devrez réparsingr vos actions pour lesquelles des exceptions peuvent être générées lorsque vous regardez comment ce code gère les exceptions. Vous allez souvent entrer dans une situation “et si …” et cela peut demander beaucoup d’efforts si vous travaillez avec des exceptions.

Re-lancer signifie que le code appelant vos EJB sera encombré d’un code de capture qui ne signifie généralement rien pour la classe appelante. Les exceptions vérifiées nb throwing des méthodes EJB signifient que vous êtes responsable de la restauration manuelle des transactions.

Outre ce qui a encore répondu par @anthares:

Parce que lorsque vous attrapez une exception, vous êtes censé le gérer correctement . Et vous ne pouvez pas vous attendre à gérer toutes sortes d’exceptions dans votre code. De même, lorsque vous attrapez toutes les exceptions, vous pouvez obtenir une exception qui ne peut pas traiter et empêcher le code supérieur de la stack de le gérer correctement.

Le principe général est de saisir le type le plus spécifique possible.

catch(Exception) est une mauvaise pratique car elle intercepte également toutes les RuntimeException (exception non vérifiée).

Mais parfois ça va! Comme si vous aviez un morceau de code qui fait quelque chose de «supplémentaire», ce dont vous ne vous souciez pas vraiment, et vous ne voulez pas que votre application fasse exploser. Par exemple, j’ai récemment travaillé sur une grande application où nos partenaires commerciaux souhaitaient que certaines transactions quotidiennes soient résumées dans un nouveau fichier journal. Ils ont expliqué que le journal n’était pas très important pour eux et que cela ne constituait pas une exigence. C’était juste quelque chose en plus qui les aiderait à comprendre les données en cours de traitement. Ils n’en avaient pas besoin, car ils pouvaient obtenir l’information ailleurs. C’est donc un cas rare où il est parfaitement acceptable d’attraper et d’avaler des exceptions.

J’ai également travaillé dans une entreprise où tous les objects Throwables ont été capturés, puis retransmis dans une exception RuntimeException personnalisée. Je ne recommanderais pas cette approche, mais je précise que c’est fait.

Je trouve deux utilisations acceptables de catch (Exception): – Au niveau supérieur de l’application (juste avant de retourner à l’utilisateur). De cette façon, vous pouvez fournir un message adéquat. – L’utiliser pour masquer les exceptions de bas niveau aux entresockets.

Le premier cas est explicite, mais laissez-moi développer le second:

Faire:

 try { xxxx } catch(Exception e) { logger.error("Error XXX",e) } 

est le masquage de bogue comme @dimitarvp dit.

Mais

 try { xxxx } catch(Exception e) { throw new BussinessException("Error doing operation XXX",e) } 

C’est une autre chose. De cette façon, vous n’ignorez pas les insectes et ne vous cachez pas sous le tapis. Vous fournissez une exception de haut niveau avec un message plus explicatif aux couches d’application supérieures.

Il est toujours important aussi de gérer les exceptions à sa couche correcte. Si vous laissez une exception de bas niveau à une couche supérieure, il est pratiquement impossible que la couche supérieure puisse la gérer correctement. Dans ce cas, je préfère masquer les exceptions de bas niveau avec une solution métier qui fournit un meilleur contexte et un meilleur message et qui dispose également de l’exception d’origine pour pouvoir accéder aux détails.

Même dans ce cas, si vous pouvez attraper des exceptions plus concrètes et que vous pouvez leur offrir un meilleur traitement, vous devez le faire.

Si, dans un bloc de code, vous pouvez obtenir une exception SQLException et une exception NetworkException, vous devez les attraper et fournir des messages et un traitement adéquats pour chacun d’eux. Mais si à la fin du bloc try / catch, vous avez une Exception le mappant avec une exception BussinessException, ça me convient. En fait, je trouve adéquat que les couches de service plus élevées ne jettent que des exceptions métier (avec des détails à l’intérieur).

N’est-ce pas un autre scénario valide pour s’assurer qu’un thread continue à capturer des exceptions à l’intérieur?

 Thread shouldRunWhenApplicationRuns = new Thread() { @Override public void run() { try { // do something that should never end } catch (Exception ex) { // log it } }; shouldRunWhenApplicationRuns.start();