N'est-ce pas une bonne pratique de gérer les exceptions d'exécution dans le code?

11

Je travaille sur une application Java et je constate que les exceptions d'exécution sont gérées à de nombreux endroits. Par exemple,

try {
    // do something
} catch(NullPointerException e) {
    return null;
}

Ma question est: quand est-ce une bonne pratique de gérer les exceptions Runtime? Quand faut-il laisser les exceptions non gérées?

Vinoth Kumar CM
la source
7
-1: Il n'y a pas de réponse unique à une question aussi large et vague. Il est impossible de fournir une réponse unique à une question aussi floue que celle-ci. Cette question est horrible. Veuillez fournir des exemples précis de cas où vous avez des doutes.
S.Lott
@ S.Lott Je suis en quelque sorte en désaccord dans ce cas car il semble qu'il y ait un sous-ensemble de programmeurs qui pensent que c'est le cas sans "bonne" rationalité.
SoylentGray
2
@Chad: "c'est le cas sans" bonne "rationalité". C'est peut-être vrai. Mais la seule réponse possible doit être "ça dépend". Par conséquent, la question semble erronée.
S.Lott

Réponses:

18

Ça dépend.

Par exemple, Integer#parseIntjette NumberFormatException(qui est un RTE) si la chaîne fournie ne peut pas être analysée. Mais vous ne voulez sûrement pas que votre application plante, simplement parce que l'utilisateur a écrit "x" dans un champ de texte qui était pour des entiers? Et comment savez-vous si la chaîne peut être analysée, à moins que vous n'essayiez de l'analyser en premier? Donc dans ce cas, le RTE est juste un signal d'erreur qui devrait provoquer une sorte de message d'erreur. On pourrait dire que ce devrait être une exception vérifiée, mais que pouvez-vous faire - ce n'est pas le cas.

Joonas Pulakka
la source
2
Je suis d'accord avec "Cela dépend", mais votre exemple d'analyse semble être plutôt un cas de mauvaise conception d'API. Integer#parseIntdevrait vraiment retourner un à la Maybe<Integer>place et ne lever aucune exception du tout.
Jörg W Mittag
3
@ Jörg W Mittag: Je conviens que c'est une mauvaise conception d'API, mais c'est le monde réel avec lequel nous devons composer. Comment gérer correctement les valeurs jetables / de retour dépend de la façon dont le monde fonctionne réellement , et non de la façon dont il devrait fonctionner de manière optimale :-)
Joonas Pulakka
Le point ici est que vous pouvez faire quelque chose de significatif pour une condition anticipée (entrée utilisateur non entière). Avaler simplement NPE est un mauvais style et couvrira simplement les erreurs de programmation existantes.
Jürgen Strobel
7

NullPointerExceptions sont généralement le signe d'une vérification nulle manquante. Donc, au lieu de l'attraper comme ça, vous devez ajouter la vérification nulle appropriée pour être sûr de ne pas lever l'exception.

Mais parfois, il est approprié de gérer les RunTimeExceptions. Par exemple, lorsque vous ne pouvez pas modifier le code pour ajouter la vérification null à l'endroit approprié, ou lorsque l'exception est autre chose qu'une NullPointerException.

Votre exemple de gestion des exceptions est terrible. Ce faisant, vous perdez la trace de la pile et des informations précises sur le problème. Et vous ne le résolvez pas, car vous déclencherez probablement une autre exception NullPointerException à un endroit différent et obtiendrez des informations trompeuses sur ce qui s'est passé et comment le résoudre.

deadalnix
la source
1
Je voudrais ajouter qu'un contrôle nul est une meilleure décision en termes de performances.
Mahmoud Hossam
... encore, si vous faites des dizaines d'allocations qui "ne devraient jamais échouer" autour d'un seul endroit, l'ajout de contrôles nuls pour chacun d'eux peut ridiculement obscurcir le code. Une exception fourre-tout (qui va gérer la situation avec élégance, pas seulement return null;) sera une meilleure solution.
SF.
Vous confondez probablement Java avec autre chose (C ++ par exemple). Lorsqu'une allocation échoue, vous obtenez une OutOfMemoryError ou quelque chose de similaire, jamais un pointeur nul. Masquer un retour nul au lieu d'une exception, c'est masquer l'erreur en attendant que le code explose ailleurs.
deadalnix
newjette std::bad_allocen C ++.
R. Martinho Fernandes
En supposant que le nouvel opérateur n'est pas surchargé, ce qui est une pratique courante. En C ++, tout peut arriver;) Mais OK, disons le malloc de C. Le point important était que vous n'avez jamais obtenu cela en Java.
deadalnix
4

Je gère les exceptions attendues là où je les attends. (Comme les erreurs de lecture / écriture DB). Exceptions inattendues Je bouillonne. Quelque part ailleurs peut-être attendre l'exception et avoir la logique pour cela.

SoylentGray
la source
2

Les exceptions devraient être juste que .. des exceptions. La meilleure pratique lors de l'utilisation d'exceptions est de les utiliser pour couvrir la situation dans laquelle quelque chose de contraire à ce que vous attendez se produit. L'exemple classique est l'exception FileNotFoundException qui est levée lorsqu'un fichier n'est tout simplement pas là. Si vous testez l'existence du fichier, vous utilisez File.exists () car vous vous contentez de pousser avec un bâton de 10 pieds pour voir si vous frappez quelque chose.

Techniquement, vous pourriez obtenir les mêmes résultats en l'entourant d'une tentative de capture et en utilisant le fichier comme s'il existait, mais A) les exceptions sont généralement coûteuses en termes de ressources et B) les programmeurs vont supposer que vous vouliez dire que le fichier existe s'il était dans une prise d'essai, ce qui ajoute à la confusion globale d'un programme.

Il existe de nombreuses situations dans lesquelles j'écrirai une méthode qui récupère une valeur dans une base de données. Un millier de choses pourraient mal tourner, et vu que je n'ai besoin que d'une petite information, il n'est pas commode d'entourer l'appel d'une liste de captures d'essai qui contient 5 exceptions différentes. Donc, je vais attraper des exceptions dans la méthode fetch. Si quelque chose ne va pas, je prends toutes les mesures appropriées pour fermer la connexion à la base de données ou tout le reste dans la clause finally et retourner null. C'est une bonne pratique non seulement parce qu'elle simplifie votre code mais aussi parce que "null" envoie le même message que vous auriez pu recevoir d'une exception .. que quelque chose ne s'est pas passé comme prévu. Gérez les spécificités des exceptions dans la méthode de récupération, mais gérez quoi faire lorsque les choses ne se passent pas

Par exemple:

Integer getUserCount() {
   Integer result = null;
   try {
      // Attempt to open database and retrieve data
   } catch (TimeoutException e) {
      logger.error("Got a watch?");
   } catch (MissingDatabaseException e) {
      logger.error("What are you smoking?");
   } catch (PermissionsToReadException e) {
      logger.error("Did you *really* think you were getting away with that?");
   } catch (PressedSendButtonToHardException e) {
      logger.error("Seriously.. just back away from the computer... slowly..");
   } catch (WTFException e) {
      logger.error("You're on your own with this one.. I don't even know what happened..");
   } finally {
      // Close connections and whatnot
   }
   return result;
}

void doStuff() {
   Integer result = getUserCount();
   if(result != null) {
       // Went as planned..
   }
}
Neil
la source
6
Si vous utilisez File.exists () et comptez sur le résultat, une condition de concurrence critique peut se produire si le fichier est supprimé entre File.exists () et File.open (). Si cela déclenche un bogue critique pour la sécurité, un attaquant pourrait provoquer cette condition exprès. Pour cette raison, il est parfois préférable de conserver l'opération atomique, c'est-à-dire de l'essayer et d'attraper l'exception.
user281377
1
En outre, certains fichiers doivent exister pour l'exécution de l'application. Ce seraient des conditions exceptionnelles. S'il y a un fichier que vous devez avoir pour que l'application fonctionne, il n'y a aucune raison de ne pas le lire et de gérer l'exception pour le cas exceptionnel. Je crois que cela rend l'intention plus claire.
Thomas Owens
C'est une mauvaise décision de retourner null. Il en résultera à un moment donné NullPointerException et il sera très difficile de déboguer ce qui s'est mal passé. Parce que quelqu'un oubliera à un moment donné le chèque nul.
deadalnix
@deadalnix: Je pourrais dire que vous pourriez tout aussi facilement oublier d'entourer avec un try-catch autrement. La différence est une question de style, pas de fonctionnalité.
Neil
@ammoQ: Je ne suis pas d'accord. Je pense que vous devriez utiliser File.exists () et dans les rares circonstances où il est supprimé avant de l'utiliser, une exception est plus que appropriée. La différence est où vous gardez vos prises. Ayez simplement un récupérateur d'exceptions générales pour les erreurs imprévues afin de vous connecter et de le signaler.
Neil
-5

oui, la gestion des exceptions d'exécution n'est pas une bonne pratique, car elle est considérée comme coûteuse / gourmande en mémoire.

prasonscala
la source
5
Bonjour prassee, pouvez-vous développer votre réponse? Les lignes simples qui ne sont pas étayées par des faits, des références ou des expériences ne sont pas très utiles.