Est-il possible d'avoir une déclaration de capture vide?

58

J'y ai réfléchi et je ne pouvais pas donner d'exemple. Pourquoi quelqu'un voudrait-il intercepter une exception sans rien faire? Pouvez-vous donner un exemple? Peut-être que c'est juste quelque chose qui ne devrait jamais être fait.

Ysolik
la source
Et enfin?
Chris
2
btw - cela a été demandé à SO l'année dernière: stackoverflow.com/questions/1234343/…
warren
17
il devrait au moins contenir un commentaire expliquant pourquoi il est vide.
peterchen

Réponses:

77

Je le fais tout le temps avec des choses comme les erreurs de conversion en D:

import std.conv, std.stdio, std.exception;

void main(string[] args) {  
    enforce(args.length > 1, "Usage:  foo.exe filename");

    double[] nums;

    // Process a text file with one number per line into an array of doubles,
    // ignoring any malformed lines.
    foreach(line; File(args[1]).byLine()) {
        try {
            nums ~= to!double(line);
        } catch(ConvError) {
            // Ignore malformed lines.
        }
    }

    // Do stuff with nums.
}

Cela dit, je pense que tous les blocages doivent contenir quelque chose , même s'il ne s'agit que d'un commentaire expliquant pourquoi vous ignorez l'exception.

Edit: Je tiens également à souligner que si vous voulez faire quelque chose comme ceci, vous devez faire attention à ne capturer que l'exception spécifique que vous souhaitez ignorer. Faire du bon vieux catch {}est presque toujours une mauvaise chose.

Dsimcha
la source
15
+1 pour commentaire d'explication.
Michael K
Certains IDE vous permettent d'indiquer qu'un nom particulier pour l'exception (généralement "ignorer") indique que vous l'ignorez volontairement, ce qui supprime l'avertissement qu'il afficherait autrement; cela prend la place du commentaire.
Alex Feinman
Je ne connais pas bien D, mais je suppose qu'il est possible de faire quelque chose comme bool TryParse (chaîne de caractères, out double valToParse), qui peut être plus propre.
Ysolik
4
Wow, quelqu'un qui utilise réellement D! :-P
James McNellis
4
Comme @Michael dit - ce n'est pas tout à fait vide puisque vous avez le commentaire là-bas; il devrait être obligatoire d'ajouter un commentaire "cette capture intentionnellement laissée en blanc" s'il n'y a pas de déclaration
STW
50

Un exemple où je pense qu'il est correct de simplement avaler une exception sans rien faire, même en enregistrant l'exception, est à l'intérieur du code de journalisation lui-même.

Si vous essayez de vous connecter à quelque chose et que vous avez une exception, vous ne pouvez rien y faire:

  • vous ne pouvez pas vous connecter bien sûr;
  • vous pourrez peut-être recourir à un mécanisme de journalisation de réserve, mais la plupart des applications ne sont pas aussi sophistiquées et, pour celles qui le sont suffisamment, le même problème de conception se posera avec le mécanisme de journalisation de réserve;
  • fast fail - sera une solution trop radicale pour la plupart des applications;
  • le fait de lancer une exception ne servira à rien car cela aboutira dans une déclaration catch qui va presque certainement essayer de la journaliser ...

Cela vous laisse avec l'option "le moins du mal" de l'avaler tranquillement, ce qui permet à l'application de continuer à exécuter son travail principal, tout en compromettant la capacité de le dépanner.

kdubinets
la source
10
excellent point. déboguer le code de débogage est toujours un défi.
DevSolo
7
Ceci, un million de fois. Surtout quand vous considérez que si vous vous connectez, vous pouvez être dans un état terrible; vous pourriez être à court de mémoire, pourrait tomber en panne, pourrait être n'importe quoi. À ce stade, lorsque vous enregistrez une erreur et CELA échoue, la seule chose responsable à faire est de ne rien faire. vous n'avez aucune garantie que tout ce que vous essayez ne fera pas empirer les choses.
GWLlosa
Excellent point. Dans mon code de journalisation, j'aime également ajouter InnerMessage pour l'exception. Plusieurs fois, cela est nul, donc essayer de l'ajouter ferait exploser la journalisation elle-même.
Tangurena
@ Tangurena Si elle est souvent nulle alors résolvez-la, ne faites pas sauter. En C #, je garde souvent de telles choses par ?? "";
Loren Pechtel
8

Si une exception est néanmoins générée par une opération facultative, il se peut que rien ne soit fait. Il pourrait ne pas être utile de le connecter. Dans ce cas, vous voudrez peut-être simplement l'attraper et ne rien faire.

Si vous faites cela, incluez un commentaire. Toujours commenter tout ce qui ressemble à un bogue (erreur dans une switchinstruction, catchbloc vide , affectation dans une condition).

Vous pourriez faire valoir que ce n'est pas un bon usage des exceptions, mais c'est pour une autre question.

David Thornley
la source
6

Les catchblocs vides sont une odeur de code dans la plupart des langues. L'idée principale est d'utiliser des exceptions pour des situations exceptionnelles et de ne pas les utiliser pour un contrôle logique. Toutes les exceptions doivent être traitées quelque part.

En conséquence de cette approche, lorsque vous programmez une couche d'application particulière, vous avez plusieurs choix:

  • ne fais rien à l'exception. Il sera attrapé et manipulé par une couche différente
  • attrapez-le et effectuez l'action corrective.
  • attraper, faire quelque chose, mais re-jeter pour une autre couche à gérer

Cela ne laisse pas vraiment de place pour ne rien faire, des catchblocs vides .

MODIFIÉ À AJOUTER : supposons que vous programmez dans un langage dans lequel le lancement d’exceptions est le moyen habituel de contrôler la logique du programme (une des alternatives à goto). Ensuite, un catchbloc vide dans un programme écrit dans cette langue ressemble beaucoup à un elsebloc vide dans une langue traditionnelle (ou pas de elsebloc du tout). Cependant, je pense que ce n'est pas le style de programmation recommandé par les communautés de développement C #, Java ou C ++.

Azheglov
la source
Je pense que l'utilisation d'exceptions comme contrôle logique est devenue assez courante, alors je me retrouve assez souvent avec des blocs catch vides ou presque vides.
Whatsisname
+1 pour reconnaître qu'un bloc catch vide pourrait indiquer l'utilisation d'exceptions pour le contrôle de flux.
John M Gant
L'utilisation d'exceptions pour la logique de programmation est généralement considérée comme une mauvaise pratique. Mais, étonnamment (mon argument initial contre les exceptions), les exceptions n’entraînent aucune perte de performance notable. Voir codeproject.com/KB/exception/ExceptionPerformance.aspx .
Evan Plaice
6

Dans certains cas, Java nécessite que vous gériez une exception qui ne peut en aucun cas se produire. Considérons ce code:

try {
   bytes[] hw = "Hello World".getBytes("UTF-8");
}
catch(UnsupportedCodingException e) {
}

Toute implémentation de la plate-forme Java doit prendre en charge les jeux de caractères standard suivants.

...

UTF-8

Sans casser votre plate-forme Java, il n'y a simplement aucun moyen de causer cette exception. Alors pourquoi s'embêter à le manipuler? Mais vous ne pouvez pas simplement omettre la clause try-catch-clause.

utilisateur281377
la source
1
Dans de tels cas, je serais tenté d'ajouter throw new Error(e)simplement pour être absolument sûr de ne rien manquer (ou de signaler une plate-forme réellement endommagée).
Halle Knast,
@HalleKnast Oui. Cela a été discuté en détail ici: softwareengineering.stackexchange.com/questions/122233/…
user281377
5

En règle générale, non. Vous voulez soit éjecter l'exception dans la pile, soit enregistrer ce qui s'est passé.

Cependant, je le fais souvent lorsque je suis en train d'analyser des chaînes et de les convertir en nombres (en particulier dans les projets de mappage qui sont du type use-once et à jeter).

boolean isNonZeroNumber = false;

try {
   if(StringUtils.isNotBlank(s) && new BigDecimal(s).compareTo(BigDecimal.ZERO) != 0) {
     b = true;
   }
} catch(NumberFormatException e) {
//swallow this exception; b stays false.
}

return b;
Fil
la source
3

Dans certains cas, l'exception n'est pas du tout exceptionnelle. en fait, c'est prévu. Considérons cet exemple:

    /* Check if the process is still alive; exitValue() throws an exception if it is */
    try {
        p.exitValue();
        processPool.remove(p);
    }
    catch (IllegalThreadStateException e) { /* expected behaviour */ }

Comme il n’existe pas de méthode isAlive () dans java.lang.Process (), le seul moyen de vérifier s’il est toujours en vie est d’appeler exitValue (), qui lève une exception IllegalThreadStateException si le processus est toujours en cours d’exécution.

utilisateur281377
la source
2

Dans mon humble expérience, c'est rarement une bonne chose. Votre kilométrage peut varier cependant.

Presque chaque fois que j'ai vu cela dans notre base de code, c'est parce que j'ai trouvé un bogue caché par l'exception mangée. En d'autres termes, en ne fournissant aucun code, l'application n'a aucun moyen d'indiquer une erreur ou d'effectuer une autre action.

Parfois, au niveau des couches d'API, par exemple, vous pouvez ne pas vouloir ou ne pas être capable de laisser les exceptions passer, alors dans ce cas, j'ai tendance à essayer d'attraper les plus génériques, puis de les consigner. Encore une fois, pour au moins donner une chance à une session de débogage / diagnostic.

En règle générale, si elle doit être vide, le moins que je puisse faire est de mettre une affirmation, ce qui fait qu'au moins quelque chose se passe pendant une session de débogage. Cela dit, si je ne peux pas le supporter, j'ai tendance à les omettre complètement.

DevSolo
la source
2

OMI, il y a un endroit où les déclarations de captures vides sont correctes. Dans les cas de test où vous attendez une exception:

try
{
   DoSomething(); //This should throw exception if everything works well
   Assert.Fail('Expected exception was not thrown');
}
catch(<whatever exception>)
{
    //Expected to get here
}
Victor Hurdugaci
la source
+1, je déteste le faire mais cela fonctionne dans JUnit
sal
@sal: qu'en est-il de @Test (attendu = Exception.class)?
Ysolik
@ysolik, mauvaise habitude
sal
1
@sal: Pourquoi est-ce une mauvaise habitude?
Adam Lear
ummmm. il existe des moyens de le faire avec des frameworks de tests unitaires. Ex. NUnit. Dans certains cas, il peut être utile de tester que quelque chose a échoué. Bien que je ne le ferais jamais dans le code de production.
Evan Plaice
2

Je crois qu’il est justifié d’avoir une clause de capture vide dans certains cas. Il s’agit de cas dans lesquels vous voulez que le code continue de fonctionner même si une opération en particulier échoue. Cependant, je pense que ce schéma peut facilement être surutilisé, il est donc important d’examiner chaque utilisation de près afin de s’assurer qu’il n’ya pas de meilleure façon de la gérer. En particulier, cela ne devrait jamais être fait s'il laisse le programme dans un état incohérent ou si cela pourrait entraîner l'échec ultérieur d'une autre partie du code.

o. Nate
la source
1

Je ne crois pas ne pas avoir un certain niveau d'alerte lorsqu'une exception se produit - l'un des objectifs de la programmation ne devrait-il pas être d'améliorer le code? Si une exception survient 10% du temps et que vous ne le savez jamais, elle sera toujours aussi mauvaise ou pire.

Cependant, je vois l’autre côté, à savoir que si l’exception ne nuit pas vraiment au traitement du code, pourquoi y exposer l’utilisateur. La solution que j'implémente généralement est de la journaliser par ma classe de consignateur (c'est-à-dire dans chaque classe que j'écris au travail).

S'il s'agit d'une exception bénigne, j'appelle la méthode .Debug () de mon enregistreur; sinon, Logger.Error () (et (peut-être) jeté).

try
{
   doWork();
}
catch(BenignException x)
{
  _log.Debug("Error doing work: " + x.Message);
}

Soit dit en passant, dans mon implémentation de mon enregistreur, un appel à la méthode .Debug () ne l'enregistrera que si mon fichier App.Config spécifie que le niveau de journalisation de l'exécution du programme est en mode débogage.

Tim Claason
la source
Que faire si _log.Debug lève une exception (pour quelque raison que ce soit)?
JohnL
Ensuite, .Debug () mange l'exception et je ne le sais jamais. Mais je me sens beaucoup plus confiant à propos de mon enregistreur que du code qui jette souvent des exceptions. Si cela me préoccupait, je suppose que je pourrais mettre en place une sorte de modèle surveillant l'entrée dans le bloc de capture et l'enregistrant pour plus tard. Dans tous les cas - point pris
Tim Claason
1

Le contrôle d'existence est un bon cas d'utilisation:

// If an exception happens, it doesn't matter. Log the initial value or the new value

function logId(person) {
    let id = 'No ID';
    try {
        id = person.data.id;
    } catch {}
    console.log(id);
}

Un autre cas est celui où une finallyclause est utilisée:

 function getter(obj){}

 function objChecker()
   {
   try
     {
     /* Check argument length and constructor type */
     if (getter.length === 1 && getter.constructor === Function)
       {
       console.log("Correct implementation");
       return true;
       }
     else
       {
       console.log("Wrong implementation");
       return false;
       }
     }
   catch(e)
     {
     }
   finally
     {
     console.log(JSON.stringify(getter))
     }
   }

 // Test the override of the getter method 
 getter = getter;
 objChecker();
 getter = [];
 objChecker();
 getter = {};
 objChecker();
 getter = RegExp;
 objChecker();
 getter = Function;
 objChecker();

Il est proposé d'autoriser l' omission de la liaison de capture dans ECMAScript pour ce cas d'utilisation et d'autres similaires.

Références

Paul Sweatte
la source
Autre exemple: dans nodejs, la méthode fs.exists (qui renvoie true ou false) est obsolète ( nodejs.org/dist/latest-v10.x/docs/api/… ) en faveur de fs.access qui lève une exception dans Si un fichier n'existe pas. Si l'on veut faire quelque chose que si le fichier existe, la clause catch est totalement inutile.
systemovich
0

La seule fois où j'ai vraiment eu besoin de faire quelque chose comme ça, c'est avec une classe de journalisation pour une application console. Un gestionnaire d'attrape global de niveau supérieur a émis l'erreur sur STDOUT, a consigné l'erreur dans un fichier, puis a fermé l'application avec un code d'erreur> 0.

Le problème ici était que, parfois, l'enregistrement dans le fichier échouait. Les autorisations de répertoire vous ont empêché d'écrire le fichier, le fichier était exclusivement verrouillé, peu importe. Si cela se produisait, je ne pourrais pas gérer l'exception de la même manière que j'avais ailleurs (attraper, consigner les détails pertinents , incorporer un type d'exception mieux, etc.), car la consignation des détails de l'exception a amené le consignateur à exécuter les mêmes actions ( essayant d'écrire dans un fichier) qui avait déjà échoué. Quand ils ont encore échoué ... Vous voyez où je vais. Il entre dans une boucle infinie.

Si vous supprimez certains blocs try {}, vous pouvez vous retrouver avec l'exception apparaissant dans une boîte de message (ce que vous ne souhaitez pas pour une application de configuration silencieuse). Donc, dans cette méthode qui écrit dans le fichier journal, j'ai un gestionnaire de captures vide. Cela n'enterre pas l'erreur car vous obtenez toujours le code d'erreur> 0, cela arrête simplement la boucle infinie et permet à l'application de se fermer normalement.

Il y a bien sûr un commentaire expliquant pourquoi c'est vide.

(J'allais poster ceci plus tôt, j'avais juste peur de tomber dans l'oubli. Comme je ne suis pas le seul, cependant ...)

JohnL
la source
0

Il est normal que certaines séquences soient exécutées quelle que soit la pièce la plus critique placée à la fin.

Par exemple. En communication de contrôle de mouvement de l'hôte au contrôleur. Dans les situations d'urgence, il existe un certain nombre d'étapes de préparation pour interrompre le mouvement, arrêter la génération de trajectoire, décélérer les moteurs, activer les interruptions, désactiver l'amplificateur et ensuite, vous devez couper l'alimentation du bus. Tout doit se dérouler de manière séquentielle et si l'une des étapes échoue, le reste des étapes doit être exécuté de toute façon, même avec un risque accepté d'endommager le matériel. Dites même si tout ce qui précède échoue, le kill bus doit quand même arriver.

utilisateur7071
la source
Cela ne signifie pas que vous ne faites rien, mais que ce que vous faites n'abandonne pas le flux. Attrapez vos exceptions, sauvegardez-les en mémoire (pas de délai d'écriture sur le disque), puis coupez le courant dans une instruction finally. Ensuite, faites ce que vous voulez avec les informations sauvegardées.
Loren Pechtel
0

Fermeture en douceur des ressources système pour remédier à une erreur

Par exemple. Si vous utilisez un service en arrière - plan qui ne fournit pas de commentaires à l'utilisateur, vous voudrez peut - être de ne pas pousser une indication de l'erreur à l'utilisateur , mais vous ne besoin de fermer les ressources utilisées de manière gracieuse.

try
{
    // execution code here
}
catch(Exception e)
{
    // do nothing here
}
finally
{
    // close db connection
    // close file io resource
    // close memory stream
    // etc...
}

Idéalement, vous utiliseriez le blocage en mode débogage pour capturer les erreurs et les imprimer sur la console ou dans un fichier journal à des fins de test. Dans un environnement de production, on s'attend généralement à ce que les services d'arrière-plan n'interrompent pas l'utilisateur lorsqu'une erreur est générée; la sortie d'erreur doit donc être supprimée.

Evan Plaice
la source