Lancer une exception dans un blocage final est-il un problème de performances?

Dans Rational Application Developer (RAD basé sur eclipse), sous parsingur de logiciel, un commentaire de révision de code (sous Performance => section Mémoire) indique “Evitez l’instruction de projection à l’intérieur de finally”.

Comment la définition de jeter dans un blocage final affecte-t-elle les performances?

entrez la description de l'image ici

Voici l’extrait de code, nous avons déjà suggéré de changer le code pour enregistrer la trace des exceptions et ne pas lancer d’exception,

} finally { if (bufferedReader != null) { try { bufferedReader.close(); } catch (final IOException ex) { throw ex; } } } 

Je me demandais simplement comment cela pourrait affecter la mémoire et les performances?

Une exception levée à partir du bloc finally remplacera toute exception levée à partir de l’ try , et les informations sur le problème réel risquent d’être perdues.

Puisque le bloc try-finally est autorisé à IOException une IOException dans ce cas, voici une meilleure façon de l’écrire:

 try (BufferedReader bufferedReader = Files.newBufferedReader(Paths.get("file.txt"))) { /* Work with `bufferedReader` */ } 

Cela ferme automatiquement le lecteur lorsque le bloc se termine et gère correctement les exceptions résultantes, même si le code Throwable dans le bloc try lance sa propre exception en premier, à l’aide du mécanisme de “suppression” de Throwable .

Si le bloc try termine sans exception, le résultat sera le résultat de la fermeture de la ressource (exception ou non). Si le bloc try lève une exception, ce sera le résultat exceptionnel. Mais si la méthode close() lève également une exception, elle sera ajoutée à l’exception du bloc try en tant qu’exception “supprimée”. Vous pouvez l’interroger par programme et lorsque la trace de la stack est imprimée, l’exception supprimée s’affiche, un peu comme les exceptions “provoquées par” que vous connaissez peut-être mieux.

Et, vous pouvez essayer avec plusieurs ressources; ceux-ci seront tous fermés et plusieurs exceptions de fermeture peuvent être supprimées.

Cela suppose que vous utilisez des E / S sur fichier, mais la même structure “try-with-resources” fonctionnera sur tout ce qui implémente AutoCloseable (stream, objects SQL, etc.).

Ce n’est pas un problème de performance. C’est un problème de correction. (Le commentaire de Marko Topolnik selon lequel l’avertissement est mal classifié me semble correct. La seule façon pour moi de percevoir un angle de performance est que si une exception levée dans le bloc try est masquée, les efforts déployés pour le créer et sa trace sont perdus. Mais c’est loin d’être le plus gros problème.)

Deux raisons pour ne pas lancer une exception dans un bloc finally:

  • Le fait de laisser une exception renvoyée par le bloc finally permet de masquer toute exception émise dans le bloc try. Ainsi, vous perdez l’exception utile d’origine et ne laissez aucun indice dans les journaux pour savoir ce qui s’est réellement passé.

  • Lorsque votre stream de contrôle normal est interrompu suite à une exception déclenchée à la fermeture, vous risquez de laisser un petit problème d’E / S transitoire (sur lequel vous n’avez aucun contrôle et qui n’affectait pas votre logique métier). travail accompli (par exemple, la transaction en cours pourrait être annulée). Cela peut dépendre du type de ressource impliqué. peut-être y a-t-il des cas où vous voudrez vraiment échouer si la clôture ne se produit pas correctement, mais pour beaucoup de cas courants (comme JDBC), il n’y a aucune bonne raison de s’en soucier.

L’utilisation réussie de try-with-resources exclut la possibilité de masquer les exceptions. Cependant, si la logique d’essai se termine sans exception, elle permet de propager tout ce qui est renvoyé lors d’une fermeture rapprochée. Comme il s’agit d’un ajout de langue, Oracle doit adopter l’approche la plus prudente. Sachez simplement ce que vous faites quand vous l’utilisez.

Solution idéale:

 try (BufferedReader bufferedReader = ...) { //do stuff } 

Mais peut-être que vous êtes en Java 1.6:

 BufferedReader bufferedReader = null; try{ bufferedReader = ...; //do stuff } finally { if (bufferedReader != null) { try { bufferedReader.close(); } catch (final IOException ex) { logger.error("Problem while cleaning up.", ex); } } } 

En dernier bloc, vous pouvez appeler une autre méthode en passant l’object B à nettoyer. Et vous pouvez avoir attraper finalement des blocs dans cette méthode.

C’est bien si vous avez des méthodes de nettoyage pour chaque object A et B séparément, dans lesquelles vous manipulez essayez de bloquer les blocs. Vous pouvez appeler les deux méthodes de nettoyage des objects. Les exceptions relatives au nettoyage de chaque object sont gérées indépendamment.

Dans l’extrait de code donné, il n’y a aucun intérêt à l’instruction throw. L’exception aurait déjà été levée par la méthode bufferedReader.close (). Le bloc catch doit simplement le gérer, plutôt que de lancer une autre exception. En fait, bien que capturer une exception levée soit certainement valable dans un bloc finale, je ne peux pas vraiment penser à une raison valable pour lancer une exception dans un bloc final.

En ce qui concerne la dégradation des performances, d’un sharepoint vue anecdotique, réintégrer une exception interceptée est nettement moins efficace que le simple traitement de celle-ci.

En ce qui concerne un cas spécifique où cela serait préjudiciable, quelque chose comme cela me vient à l’esprit. Si vous utilisiez une autre méthode effectuant un nettoyage dans votre bloc finally, telle que FileOutputStream.close (), et que la première renvoyait une erreur, la seconde ne s’exécuterait jamais, car l’instruction throw met fin au traitement du bloc. À ce stade, vous perdriez des ressources.

Donc, pour résumer, try / catch sont bien dans un bloc final, mais l’utilisation de l’instruction de projection devrait être évitée pour des raisons d’efficacité et de conséquences inattendues (fuite de mémoire).

Enfin, est utilisé après la levée / interception d’une exception. Donc, par conception, il n’est pas nécessaire de lancer une exception. Cela ne devrait être fait que dans votre bloc try.

Cela pourrait vous aider à en savoir plus sur la gestion des exceptions try-catch-finally en Java.