web-dev-qa-db-fra.com

Pourquoi les blocs de prise vides sont-ils une mauvaise idée?

Je viens de voir une question sur try-catch , quelles personnes (y compris Jon Skeet) disent que les blocs de capture vides sont une très mauvaise idée? Pourquoi ça? N'y a-t-il pas une situation où 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 (webservice, base de données) et vous ne vous souciez vraiment pas de savoir si vous obtiendrez ces informations ou non. Donc, vous essayez de l'obtenir, et si quelque chose se passe, ça va, je vais simplement ajouter un "catch (Exception ignored) {}" et c'est tout

174
Samuel Carrijo

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 de la programmation de mettre du ruban noir sur un voyant d'avertissement du moteur.

Je pense que la manière dont vous traitez les exceptions dépend de la couche de logiciel dans laquelle vous travaillez: Exceptions in the Rainforest .

286
Ned Batchelder

Ils sont une mauvaise idée en général parce qu'il s'agit d'une condition vraiment rare dans laquelle un échec (une condition exceptionnelle, plus générique) n'est correctement rencontré avec AUCUNE réponse. En plus de cela, les blocs vides catch sont un outil couramment utilisé par les personnes qui utilisent le moteur d'exceptions pour vérifier les erreurs qu'elles devraient faire par anticipation.

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 de toute façon (par exemple, lors de l’écriture d’une erreur précédente dans un fichier journal texte). vous obtenez un IOException, ce qui signifie que vous ne pouvez pas écrire la nouvelle erreur de toute façon).

35
Adam Robinson

Je n'irais pas jusqu'à 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, je me moque bien si le serveur lève une exception parce que le client est déconnecté et que index.html n'a pas pu être envoyé.

10
lubos hasko

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

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

Donc, cela pourrait aller (selon votre application) à faire:

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

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

8
Daniel Pryden

Des blocs de capture vides sont généralement insérés car le codeur ne sait pas vraiment ce qu'il fait. Dans 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 finally {}, un seul est requis.

6
Justin

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 un particulier raison, et vous vous attendez à cette exception et ne le faites vraiment pas. besoin de faire quelque chose à ce sujet.

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

6
balpha

Par Josh Bloch - Point 65: Ne pas ignorer les exceptions de Effective Java:

  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 est approprié d'ignorer l'exception.
5
KrishPrabakar

Cela va de pair avec "N'utilisez pas d'exceptions pour contrôler le flux de programmes" et "Utilisez uniquement des exceptions dans des circonstances exceptionnelles". Si cela est fait, alors des 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 qu'échouer, c'est échouer en silence.

3
Imagist

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

C'est similaire au On Error Resume Next De VB6, sauf que tout ce qui est dans le bloc try après que l'exception soit levée sera ignoré.

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

3
Powerlord

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 forcément mauvais d’avaler une exception et de retourner false, null ou une autre valeur dans certains cas. Le framework .net a beaucoup de méthodes "try" 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.

2
complexcipher

Je trouve le plus énervant avec les déclarations 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 doivent 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. Activé uniquement en mode débogage)

1
Anders

En règle générale, vous ne devez intercepter que les exceptions que vous pouvez réellement gérer. Cela signifie que vous devez être aussi spécifique que possible lorsque vous interceptez 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 quelque exception que ce soit, vous êtes capturé, il est "manipulé" en tentant de nouveau 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.

Gardez à l'esprit que vous ne devriez implémenter un finaliseur que si vous en avez réellement besoin et même dans ce cas, vous devriez 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.

1
Brian Rasmussen

Il y a des situations où 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 publier 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 sera simplement un obstacle, et la journalisation de l'exception produira probablement simplement des milliers de messages "en échec à XXX" .

  • programmes qui ne peuvent pas échouent, bien qu'ils devraient au moins enregistrer quelque chose.

pour la plupart des applications winforms, j'ai constaté qu'il suffisait d'avoir une seule instruction try pour chaque entrée d'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 des appels afin qu'une exception ne génère pas une quantité infinie de messages.

1
Dave Cousineau

Parce que si une exception is est levée, 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"!

1
Nate

Les blocs d'arrêt 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.

1
Dan

Ce n'est probablement jamais la bonne chose parce que vous passez en silence chaque exception possible. Si vous attendez une exception spécifique, vous devriez alors 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;
}
1
xanadont
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. Donc, vous essayez de l'obtenir, et si quelque chose se passe, ça va, je vais simplement ajouter un "catch (Exception ignored) {}" et c'est tout

Donc, avec votre exemple, c'est une mauvaise idée dans ce cas parce que vous attrapez et ignorez les exceptions all. Si vous attrapiez seulement EInfoFromIrrelevantSourceNotAvailable et que vous l'ignoriez, ce serait bien, mais vous ne l'êtes pas. Vous ignorez également ENetworkIsDown, ce 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 capturer (et ignorer) uniquement des exceptions de certains types que vous savez être sans importance. Les situations dans lesquelles il est judicieux de supprimer et d'ignorer silencieusement les exceptions toutes, sans arrêter de les examiner d'abord pour déterminer si elles sont attendues/normales/non pertinentes ou non sont extrêmement rares.

1
Dave Sherohman

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

0
Chadit