web-dev-qa-db-fra.com

Pourquoi le Catch (Exception) est-il presque toujours une mauvaise idée?

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

51
Nasser Hadjloo

Parce que lorsque vous attrapez une exception vous êtes censé la gérer correctement . Et vous ne pouvez pas vous attendre à gérer toutes sortes d'exceptions dans votre code. De même, lorsque vous interceptez toutes les exceptions, vous pouvez obtenir une exception qui ne peut pas gérer et empêcher le code situé en haut de la pile de le gérer correctement.

Le principe général est d’attraper le type le plus spécifique possible. 

52
anthares

Petite histoire: ça s'appelle le masquage des bogues. Si vous avez un morceau de code qui ne fonctionne pas bien et que vous lancez des exceptions (ou si vous transmettez une entrée mal formée à ce morceau de code) et que vous aveuglez les yeux en détectant toutes les exceptions possibles, vous ne découvrirez jamais le bogue et ne le corrigerez pas.

18
dimitarvp

Vous ne devriez intercepter 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 :-)

8
Darin Dimitrov

Parce que vous ne savez pas vraiment pourquoi une exception s'est produite, et plusieurs exceptions nécessitent le traitement correct d'une voiture très spéciale (si possible), comme une exception OutOfMemoryException et des exceptions système de bas niveau similaires.

Par conséquent, vous ne devriez intercepter que des exceptions:

  • vous savez exactement comment vous en occuper (par exemple FileNotFoundException ou autre)
  • quand vous les relancerez ensuite (par exemple, pour effectuer un nettoyage post-échec)
  • lorsque vous devez transporter l'exception vers un autre thread
5
Lucero

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 capturer 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, catch (Exception) peut être correct. Par exemple:

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

Je trouve deux utilisations acceptables de catch(Exception):

  • Au niveau supérieur de l'application (juste avant de revenir à l'utilisateur). De cette façon, vous pouvez envoyer un message adéquat.
  • Son utilisation pour masquer les exceptions de bas niveau comme des exceptions professionnelles.

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 bugs comme @dimitarvp dit.

Mais le ci-dessous est différent:

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

De cette façon, vous ne négligez pas les insectes et ne les 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 également toujours important de gérer les exceptions au niveau correct. Si vous transmettez une exception de bas niveau à une couche à niveau élevé, il est pratiquement impossible pour la couche supérieure de la gérer correctement.

Dans ce cas, je préfère masquer les exceptions de bas niveau avec un autre qui fournit un contexte et un message plus précis, ainsi que l'exception originale permettant de rentrer dans les détails.

Néanmoins, si vous pouvez intercepter des exceptions plus concrètes et leur fournir un meilleur traitement, vous devez le faire.

Si dans un bloc de code, vous pouvez obtenir un SQLException et un NetworkException, vous devez les intercepter et fournir des messages et un traitement appropriés pour chacun d'eux . Mais si à la fin du bloc try/catch vous avez un Exception qui le mappe BussinessException c'est correct pour moi . En fait, je le trouve adéquat lorsque des couches de service plus élevées ne lèvent que des exceptions métier (avec des détails à l'intérieur).

3
lujop

Outre ce à quoi @anthares a encore répondu:

Parce que lorsque vous attrapez une exception vous êtes censé la gérer correctement . Et vous ne pouvez pas vous attendre à gérer toutes sortes d'exceptions dans votre code. De même, lorsque vous interceptez toutes les exceptions, vous pouvez obtenir une exception qui ne peut pas gérer et empêcher le code situé en haut de la pile de le gérer correctement.

Le principe général est d’attraper le type le plus spécifique possible.

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

1
taringamberini

Mais parfois ça va! Par exemple, si vous avez un élément de code qui fait quelque chose de «supplémentaire», qui ne vous intéresse vraiment pas, et que vous ne voulez pas que votre application explose. Par exemple, j'ai récemment travaillé sur une grande application dans laquelle nos partenaires commerciaux souhaitaient qu'une transaction quotidienne soit résumée dans un nouveau fichier journal. Ils ont expliqué que le journal n'était pas très important pour eux et qu'il n'était pas considéré comme une exigence. C'était simplement un élément supplémentaire qui les aiderait à comprendre les données traitées. Ils n'en avaient pas besoin, car ils pouvaient obtenir des informations ailleurs. Il s'agit donc d'un cas rare où il est parfaitement correct d'attraper et d'avaler des exceptions.

J'ai également travaillé dans une société où tous les objets Throwables ont été capturés, puis rediffusés dans une exception RuntimeException personnalisée. Je ne recommanderais pas cette approche, mais simplement en soulignant que c'est fait.

0
MattC

Cela peut être spécifique à Java:

Parfois, vous aurez besoin d'appeler des méthodes qui jettent des exceptions vérifiées. Si cela se trouve dans votre couche logique EJB/Business, vous avez 2 choix - capturez-les ou relancez-les. 

La capture de classes d'exceptions spécifiques signifie que vous devrez ré-analyser vos actions pour lesquelles des exceptions peuvent être levées lorsque vous regardez comment ce code traite les exceptions. Vous vous retrouverez souvent dans une situation difficile et il peut être très difficile de déterminer si les exceptions sont gérées correctement.

Re-lancer signifie que le code appelant vos EJB sera jonché de code de capture qui ne signifiera généralement rien pour la classe appelante. nb Si vous lancez des exceptions vérifiées à partir de méthodes EJB, vous serez responsable de l'annulation manuelle des transactions.

0
Vincent Fleetwood

N’est-ce pas un autre scénario valable de s’assurer qu’un thread garde toujours une exception capturante en son sein?

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