Question

Je viens de voir une question sur try-catch , quelles personnes (y compris Jon Skeet) disent que les blocs d'arrêt vides sont une très mauvaise idée? Pourquoi ça? N'y a-t-il aucune situation dans laquelle une prise vide n'est pas une mauvaise décision de conception?

Je veux dire, par exemple, vous voulez parfois obtenir des informations supplémentaires quelque part (service Web, base de données) et vous ne vous souciez vraiment pas de savoir si vous obtiendrez ces informations ou non. Vous essayez donc de l’obtenir, et si quelque chose se passe, c’est correct, je vais simplement ajouter un "catch (Exception ignorée) {}". et c'est tout

Était-ce utile?

La solution

Généralement, try-catch vide est une mauvaise idée car vous avalez en silence une condition d'erreur, puis continuez son exécution. Parfois, cela peut être la bonne chose à faire, mais c'est souvent le signe qu'un développeur a vu une exception, ne savait pas quoi faire à ce sujet, et a donc utilisé un piège vide pour faire taire le problème.

C’est l’équivalent en programmation de mettre une bande noire sur un voyant d’avertissement moteur.

Je pense que la manière dont vous traitez les exceptions dépend de la couche de logiciel dans laquelle vous travaillez: Exceptions dans la forêt tropicale .

Autres conseils

C’est une mauvaise idée en général car il s’agit d’une condition vraiment rare dans laquelle un échec (condition exceptionnelle, de manière plus générique) ne donne correctement AUCUNE réponse. De plus, les blocs catch vides sont un outil couramment utilisé par les personnes qui utilisent le moteur des exceptions pour vérifier les erreurs avant qu'elles ne le soient.

Dire que c'est toujours mauvais est faux ... c'est vrai de très peu. Il peut y avoir des circonstances dans lesquelles vous ne vous souciez pas du fait qu’il ya eu une erreur ou que la présence de l’erreur indique de toute façon que vous ne pouvez rien y faire (par exemple, lors de l’écriture d’une erreur précédente dans un fichier journal texte). vous obtenez une IOException , ce qui signifie que vous ne pouvez pas écrire la nouvelle erreur de toute façon).

Je ne voudrais pas pousser les choses plus loin que de dire que celui qui utilise des blocs vides est un mauvais programmeur et ne sait pas ce qu'il fait ...

J'utilise des blocs de capture vides si nécessaire. Parfois, le programmeur de la bibliothèque que je consomme ne sait pas ce qu’il fait et jette des exceptions même dans des situations où personne n’en a besoin.

Par exemple, considérons une bibliothèque de serveur http, cela m’inquiète peu si le serveur lève une exception parce que le client est déconnecté et que index.html ne peut pas être envoyé.

Il existe de rares cas où cela peut être justifié. En Python, vous voyez souvent ce type de construction:

try:
    result = foo()
except ValueError:
    result = None

Cela peut donc être correct (selon votre application):

result = bar()
if result == None:
    try:
        result = foo()
    except ValueError:
        pass # Python pass is equivalent to { } in curly-brace languages
 # Now result == None if bar() returned None *and* foo() failed

Dans un projet .NET récent, j'ai dû écrire du code pour énumérer les DLL de plug-in afin de trouver les classes qui implémentent une certaine interface. Le bit de code pertinent (dans VB.NET, désolé) est:

    For Each dllFile As String In dllFiles
        Try
            ' Try to load the DLL as a .NET Assembly
            Dim dll As Assembly = Assembly.LoadFile(dllFile)
            ' Loop through the classes in the DLL
            For Each cls As Type In dll.GetExportedTypes()
                ' Does this class implement the interface?
                If interfaceType.IsAssignableFrom(cls) Then

                    ' ... more code here ...

                End If
            Next
        Catch ex As Exception
            ' Unable to load the Assembly or enumerate types -- just ignore
        End Try
    Next

Bien que même dans ce cas, j’admettrais que l’enregistrement de l’échec quelque part serait probablement une amélioration.

Des blocs de capture vides sont généralement insérés, car le codeur ne sait pas vraiment ce qu'il fait. Au sein de mon organisation, un bloc catch vide doit inclure un commentaire expliquant pourquoi il est judicieux de ne rien faire avec l'exception.

Sur une note connexe, la plupart des gens ne savent pas qu'un bloc try {} peut être suivi d'un catch {} ou d'un {{} final, un seul est requis.

Des exceptions ne devraient être levées que s'il existe vraiment une exception - quelque chose qui se passe au-delà de la norme. Un bloc de capture vide dit en gros "il se passe quelque chose de grave, mais je m'en fiche". C'est une mauvaise idée.

Si vous ne voulez pas gérer l'exception, laissez-la se propager vers le haut jusqu'à atteindre un code capable de la gérer. Si rien ne peut gérer l'exception, l'application devrait être supprimée.

Je pense que ce n'est pas grave si vous attrapez un type d'exception particulier dont vous savez qu'il ne sera soulevé que pour une seule raison , et vous vous attendez à cette exception et vraiment vous n'avez rien à faire à ce sujet.

Mais même dans ce cas, un message de débogage peut être en ordre.

Par Josh Bloch - Élément 65: Ne pas ignorer les exceptions de Java effectif :

  1. Un bloc catch vide va à l'encontre de l'objectif des exceptions
  2. À tout le moins, le bloc catch devrait contenir un commentaire expliquant pourquoi il convient d'ignorer l'exception.

Un bloc de capture vide indique essentiellement "Je ne veux pas savoir quelles erreurs sont générées, je vais simplement les ignorer."

Il est similaire au On Error Resume Next de VB6 , sauf que tout élément du bloc try après la levée de l'exception sera ignoré.

Ce qui n'aide pas quand quelque chose se brise.

Cela va de pair avec, "N'utilisez pas d'exceptions pour contrôler le flux de programmes", et "N'utilisez que des exceptions dans des circonstances exceptionnelles". Si cela est fait, les exceptions ne devraient se produire que lorsqu'il y a un problème. Et s'il y a un problème, vous ne voulez pas échouer en silence. Dans les rares anomalies où il n'est pas nécessaire de gérer le problème, vous devez au moins enregistrer l'exception, au cas où cette anomalie ne constituerait plus une anomalie. La seule chose pire que d’échouer, c’est d’échouer en silence.

Je pense qu'un bloc catch complètement vide est une mauvaise idée car il n'y a aucun moyen de déduire qu'ignorer l'exception était le comportement souhaité du code. Il n'est pas nécessairement mauvais d'avaler une exception et de renvoyer false, null ou une autre valeur dans certains cas. Le framework .net comporte de nombreux "essais". méthodes qui se comportent de cette façon. En règle générale, si vous avalez une exception, ajoutez un commentaire et une instruction de journalisation si l'application prend en charge la journalisation.

Parce que si une exception est émise , vous ne la verrez jamais - échouer en silence est la pire option possible - vous aurez un comportement erroné et aucune idée de regarder où cela se passe. Au moins mettre un message de journal là-bas! Même si c'est quelque chose qui "ne peut jamais arriver"!

Les blocs d'interception vides indiquent qu'un programmeur ne sait pas quoi faire avec une exception. Ils empêchent l’exception de se propager et d’être gérée correctement par un autre bloc try. Essayez toujours de faire quelque chose à l'exception que vous attrapez.

Je trouve le plus énervant avec les instructions catch vides, c’est quand un autre programmeur l’a fait. Ce que je veux dire, c’est que lorsque vous devez déboguer le code d’une autre personne, toute déclaration de capture vide rend une telle entreprise plus difficile qu’elle ne le devrait. Les instructions de capture IMHO devraient toujours afficher un type de message d'erreur - même si l'erreur n'est pas gérée, elle devrait au moins la détecter (alt. Uniquement en mode débogage)

Ce n'est probablement jamais la bonne chose à faire car vous passez en silence toutes les exceptions possibles. Si vous attendez une exception spécifique, vous devez la tester et la rediffuser si ce n’est pas votre exception.

try
{
    // Do some processing.
}
catch (FileNotFound fnf)
{
    HandleFileNotFound(fnf);
}
catch (Exception e)
{
    if (!IsGenericButExpected(e))
        throw;
}

public bool IsGenericButExpected(Exception exception)
{
    var expected = false;
    if (exception.Message == "some expected message")
    {
        // Handle gracefully ... ie. log or something.
        expected = true;
    }

    return expected;
}

En règle générale, vous ne devez intercepter que les exceptions que vous pouvez réellement gérer. Cela signifie être aussi précis que possible lors de la détection des exceptions. Attraper toutes les exceptions est rarement une bonne idée et ignorer toutes les exceptions est presque toujours une très mauvaise idée.

Je ne peux que penser à quelques cas où un bloc de capture vide a une utilité significative. Si vous faites une exception, quelle que soit l’exception spécifique que vous capturez, elle est "gérée". en réessayant simplement l'action, il n'y aurait pas besoin de faire quoi que ce soit dans le bloc catch. Cependant, il serait toujours bon de consigner le fait que l'exception s'est produite.

Autre exemple: CLR 2.0 a modifié la manière dont les exceptions non gérées sur le thread du finaliseur sont traitées. Avant la version 2.0, le processus était autorisé à survivre à ce scénario. Dans le CLR actuel, le processus est arrêté en cas d'exception non gérée sur le thread du finaliseur.

N'oubliez pas que vous ne devez implémenter un finaliseur que si vous en avez réellement besoin et même dans ce cas, vous devez en faire un peu autant que possible dans le finaliseur. Mais si tout ce que votre finaliseur doit faire peut générer une exception, vous devez choisir entre le moindre des deux maux. Voulez-vous fermer l'application en raison de l'exception non gérée? Ou voulez-vous continuer dans un état plus ou moins indéfini? Au moins en théorie, ce dernier peut être le moindre de deux maux dans certains cas. Dans ce cas, le bloc catch vide empêcherait la fin du processus.

Je veux dire, par exemple, vous voulez parfois obtenir des informations supplémentaires quelque part (webservice, base de données) et vous ne vous souciez vraiment pas de savoir si vous obtiendrez ces informations ou non. Vous essayez donc de l’obtenir, et si quelque chose se passe, c’est correct, je vais simplement ajouter un "catch (Exception ignorée) {}". et c'est tout

Alors, allez avec votre exemple, c'est une mauvaise idée dans ce cas parce que vous attrapez et ignorez toutes les exceptions. Si vous attrapiez uniquement EInfoFromIrrelevantSourceNotAvailable et que vous l'ignoriez, ce serait très bien, mais vous ne l'êtes pas. Vous ignorez également ENetworkIsDown , qui peut être important ou non. Vous ignorez ENetworkCardHasMelted et EFPUHasDecidedThatOnePlusOneIsSeventeen , qui sont presque certainement importants.

Un bloc catch vide n’est pas un problème s’il est configuré pour ne capturer (et ignorer) que des exceptions de certains types que vous savez sans importance. Les situations dans lesquelles il est judicieux de supprimer et d'ignorer silencieusement toutes toutes les exceptions, sans arrêter de les examiner d'abord pour voir si elles sont attendues / normales / non pertinentes ou non, sont extrêmement rares.

Il existe des situations dans lesquelles vous pourriez les utiliser, mais elles devraient être très rares. Les situations où je pourrais en utiliser une incluent:

  • enregistrement des exceptions; En fonction du contexte, vous souhaiterez peut-être envoyer une exception non gérée ou un message.

  • situations techniques en boucle, telles que le rendu ou le traitement du son ou un rappel de la liste déroulante, dans lesquelles le comportement lui-même va démontrer le problème, le lancement d'une exception gênera tout simplement et la journalisation de l'exception produira probablement des milliers de "a échoué à XXX" messages.

  • les programmes pour lesquels ne peut pas échouer, même s'ils doivent au moins enregistrer quelque chose.

pour la plupart des applications winforms, j’ai trouvé qu’il suffisait d’avoir une seule instruction try pour chaque entrée utilisateur. J'utilise les méthodes suivantes: (AlertBox est juste un encapsuleur rapide MessageBox.Show)

  public static bool TryAction(Action pAction)
  {
     try { pAction(); return true; }
     catch (Exception exception)
     {
        LogException(exception);
        return false;
     }
  }

  public static bool TryActionQuietly(Action pAction)
  {
     try { pAction(); return true; }
     catch(Exception exception)
     {
        LogExceptionQuietly(exception);
        return false;
     }
  }

  public static void LogException(Exception pException)
  {
     try
     {
        AlertBox(pException, true);
        LogExceptionQuietly(pException);
     }
     catch { }
  }

  public static void LogExceptionQuietly(Exception pException)
  {
     try { Debug.WriteLine("Exception: {0}", pException.Message); } catch { }
  }

Ensuite, chaque gestionnaire d'événements peut faire quelque chose comme:

  private void mCloseToolStripMenuItem_Click(object pSender, EventArgs pEventArgs)
  {
     EditorDefines.TryAction(Dispose);
  }

ou

  private void MainForm_Paint(object pSender, PaintEventArgs pEventArgs)
  {
     EditorDefines.TryActionQuietly(() => Render(pEventArgs));
  }

Théoriquement, vous pourriez avoir TryActionSilently, ce qui pourrait être mieux pour rendre les appels afin qu'une exception ne génère pas une quantité infinie de messages.

Vous ne devriez jamais avoir un bloc catch vide. C'est comme cacher une erreur que vous connaissez. À tout le moins, vous devriez écrire une exception dans un fichier journal à revoir ultérieurement si vous êtes pressé par le temps.

Si vous ne savez pas quoi faire dans catch block, vous pouvez simplement enregistrer cette exception, mais ne la laissez pas vierge.

        try
        {
            string a = "125";
            int b = int.Parse(a);
        }
        catch (Exception ex)
        {
            Log.LogError(ex);
        }
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top