Les blocs java try doivent-ils être définis aussi étroitement que possible?

On m’a dit que l’utilisation du mécanisme d’essais Java de Java entraînait des problèmes. Ainsi, bien qu’il soit nécessaire de placer des méthodes qui jettent une exception vérifiée dans un bloc try pour gérer les exceptions possibles, il est recommandé, du sharepoint vue des performances, de limiter la taille du bloc try pour ne contenir que les opérations pouvant générer des exceptions.

Je ne suis pas sûr que ce soit une conclusion raisonnable.

Considérons les deux implémentations ci-dessous d’une fonction qui traite un fichier texte spécifié.

Même s’il est vrai que le premier engendre des frais généraux inutiles, je le trouve beaucoup plus facile à suivre. Il est moins clair que les exceptions viennent justement de l’examen des déclarations, mais les commentaires montrent clairement quelles sont les déclarations responsables.

Le second est beaucoup plus long et compliqué que le premier. En particulier, le bon idiome de lecture de ligne du premier doit être modifié pour que l’appel readLine dans un bloc try.

Quelle est la meilleure pratique pour gérer les exceptions dans une fonction où plusieurs exceptions peuvent être apscopes dans sa définition?

Celui-ci contient tout le code de traitement dans le bloc try:

 void processFile(File f) { try { // construction of FileReader can throw FileNotFoundException BufferedReader in = new BufferedReader(new FileReader(f)); // call of readLine can throw IOException Ssortingng line; while ((line = in.readLine()) != null) { process(line); } } catch (FileNotFoundException ex) { handle(ex); } catch (IOException ex) { handle(ex); } } 

Celui-ci ne contient que les méthodes qui jettent des exceptions dans les blocs try:

 void processFile(File f) { FileReader reader; try { reader = new FileReader(f); } catch (FileNotFoundException ex) { handle(ex); return; } BufferedReader in = new BufferedReader(reader); Ssortingng line; while (true) { try { line = in.readLine(); } catch (IOException ex) { handle(ex); break; } if (line == null) { break; } process(line); } } 

    La prémisse de base ici est fausse: la taille d’un bloc try ne fait aucune différence en termes de performances. Les performances sont affectées par le fait de générer des exceptions lors de l’exécution, et cela indépendamment de la taille du bloc try .

    Cependant, garder de petits blocs d’essais peut mener à de meilleurs programmes.

    Vous pouvez attraper des exceptions pour récupérer et continuer, ou vous pouvez les attraper simplement pour les signaler à l’appelant (ou à un humain, via une interface utilisateur).

    Dans le premier cas, les défaillances à partir desquelles vous pouvez récupérer sont souvent très spécifiques, ce qui conduit à des blocs d’ try plus petits.

    Dans le second cas, où une exception est interceptée pour être renvoyée à une autre exception et renvoyée ou affichée à l’utilisateur, de petits blocs d’ try signifient que vous connaissez plus précisément l’opération qui a échoué et le contexte de niveau supérieur. qui cet appel a été fait. Cela vous permet de créer des rapports d’erreur plus spécifiques.

    Bien sûr, il existe… des exceptions (désolé!) À ces directives. Par exemple, dans certains cas, des rapports d’erreur très spécifiques peuvent constituer un problème de sécurité.


    Il pourrait être utile de savoir quel effet un bloc try a sur le code compilé. Cela ne change rien aux instructions compilées! (Bien sûr, le bloc catch correspondant catch , car il est comme tout autre code.)

    Un bloc try crée une entrée dans la table des exceptions associée à la méthode. Cette table comporte une gamme de compteurs d’instructions source, un type d’exception et une instruction de destination. Lorsqu’une exception est déclenchée, cette table est examinée pour voir s’il existe une entrée avec un type correspondant et une plage qui inclut l’instruction qui a généré l’exception. Si c’est le cas, l’exécution s’achemine vers le numéro de destination correspondant.

    La chose importante à réaliser est que cette table n’est pas consultée (et n’a aucun effet sur l’exécution des performances) à moins que cela ne soit nécessaire. (Négliger un peu de charge dans le chargement de la classe.)

    On m’a dit que l’utilisation du mécanisme d’essais Java de Java entraînait des problèmes.

    Absolument. Et il y a aussi des frais généraux pour les appels de méthodes. Mais vous ne devriez pas mettre tout votre code dans une seule méthode.

    Ne pas dénoter le klaxon d’optimisation prématuré, mais l’accent devrait être mis sur la facilité de lecture, l’organisation, etc. Les constructions de langage ont rarement un impact sur les performances autant que sur l’organisation du système et le choix des algorithmes.

    Pour moi, le premier est le plus facile à lire.

    Non. La seule chose que vous devriez considérer est celle où vous pouvez raisonnablement gérer l’exception et les ressources que vous devez récupérer (avec finalement).

    C’est une optimisation prématurée au pire. Ne le fais pas

    “Nous devrions oublier les petites efficacités, disons environ 97% du temps: l’optimisation prématurée est la racine de tout le mal” – Knuth.

    il y a très très peu d’avantages à la 2ème méthode. Après tout, si vous parvenez à ouvrir un fichier sans le lire, il y a quelque chose qui ne va pas avec votre ordinateur. donc savoir que l’exception io provient de la méthode readLine () est très rarement utile. de plus, comme vous le savez, différentes exceptions sont lancées pour différents problèmes (FileNotFoundException, etc.)

    tant que vous l’étendez avec un bloc “logique”, c’est-à-dire en ouvrant, en lisant et en fermant un fichier en une seule fois, j’irais avec la première méthode. Il est beaucoup plus simple de lire et, particulièrement en ce qui concerne les entrées-sorties, les cycles de traitement utilisés par la surcharge de test seraient minimes, voire inexistants.

    Placer les blocs d’essai autour du code spécifique qui peut déclencher une exception rend, à mon avis, plus facile à lire. Vous souhaiterez probablement afficher un message différent pour chaque erreur et fournir des instructions à l’utilisateur, qui seront différentes selon l’endroit où l’erreur se produit.

    Cependant, le problème de performances auquel la plupart des gens se réfèrent est lié à l’augmentation de l’exception, pas au bloc try lui-même.

    En d’autres termes, tant qu’une erreur ne se produit jamais, le bloc try n’affectera pas sensiblement les performances. Vous ne devriez pas considérer un bloc try juste une autre construction de contrôle de stream et générer une erreur pour vous connecter à votre code. C’est ce que vous voulez éviter.

    La seconde méthode générera une erreur de compilation que le reader n’a peut reader être pas été initialisé. Vous pouvez contourner ce problème en l’initialisant à null , mais cela signifie simplement que vous pouvez obtenir un NPE, et cela n’a aucun avantage.