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.
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.
Réponses:
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.
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:
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.
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 switch
instruction, catch
bloc 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.
Les catch
blocs 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:
Cela ne laisse pas vraiment de place pour ne rien faire, des catch
blocs 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 catch
bloc vide dans un programme écrit dans cette langue ressemble beaucoup à un else
bloc vide dans une langue traditionnelle (ou pas de else
bloc 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 ++.
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.
throw new Error(e)
simplement pour être absolument sûr de ne rien manquer (ou de signaler une plate-forme réellement endommagée).
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;
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.
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.
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
}
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.
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.
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 finally
clause 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
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 ...)
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.
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.