Devrait try...catch aller à l'intérieur ou à l'extérieur d'une boucle?
J'ai une boucle qui ressemble à quelque chose comme ceci:
for (int i = 0; i < max; i++) {
String myString = ...;
float myNum = Float.parseFloat(myString);
myFloats[i] = myNum;
}
C'est le contenu principal d'une méthode dont le seul but est de retourner un tableau de chars. Je veux cette méthode pour retourner null
si il y a une erreur, alors j'ai mis la boucle à l'intérieur d'un try...catch
bloc, comme ceci:
try {
for (int i = 0; i < max; i++) {
String myString = ...;
float myNum = Float.parseFloat(myString);
myFloats[i] = myNum;
}
} catch (NumberFormatException ex) {
return null;
}
Mais j'ai aussi pensé à mettre la try...catch
bloc à l'intérieur de la boucle, comme ceci:
for (int i = 0; i < max; i++) {
String myString = ...;
try {
float myNum = Float.parseFloat(myString);
} catch (NumberFormatException ex) {
return null;
}
myFloats[i] = myNum;
}
Est-il une raison, de la performance ou autrement, de préférer l'un sur l'autre?
Edit: Le consensus semble être que c'est plus propre de mettre la boucle à l'intérieur de la try/catch, éventuellement à l'intérieur de sa propre méthode. Cependant, il y a toujours un débat sur qui est plus rapide. Quelqu'un peut essayer et revenir avec une réponse unifiée?
- Je ne sais pas à propos de la performance, mais le code est plus propre avec le try catch en dehors de la boucle for.
Vous devez vous connecter pour publier un commentaire.
PERFORMANCE:
Il n'y a absolument aucune différence de performances lorsque le try/catch structures sont placées. En interne, ils sont mis en œuvre comme un code-fourchette de table dans une structure qui est créé lorsque la méthode est appelée. Bien que la méthode est en cours d'exécution, le try/catch structures sont complètement hors de la photo, à moins qu'un jet de produit, alors l'emplacement de l'erreur est comparée à la table.
Voici une référence: http://www.javaworld.com/javaworld/jw-01-1997/jw-01-hood.html
La table est décrite environ à mi-chemin vers le bas.
Performance: comme Jeffrey dit dans sa réponse, en Java il n'a pas beaucoup de différence.
Généralement, pour des raisons de lisibilité du code, votre choix de l'endroit pour attraper l'exception dépend si vous voulez que la boucle afin que le traitement ou pas.
Dans votre exemple, vous retourné lors de l'interception d'une exception. Dans ce cas, je mettrais le try/catch autour de la boucle. Tout simplement si vous voulez attraper une mauvaise valeur, mais de poursuivre le traitement, la mettre à l'intérieur.
La troisième voie: Vous pouvez toujours écrire votre propre statique ParseFloat méthode et ont la gestion des exceptions est traité dans cette méthode plutôt que de votre boucle. Faire la gestion des exceptions isolées dans la boucle elle-même!
Tout droit, après Jeffrey L Whitledge dit qu'il n'y a pas de différence de performances (en 1997), je suis allé et l'a testé. J'ai couru ce petit indice:
J'ai vérifié l'résultant de pseudo-code binaire à l'aide de javap pour s'assurer que rien n'a été insérée.
Les résultats ont montré que, en supposant négligeable optimisations JIT, Jeffrey est correct; il n'y a absolument pas de différence de performances sur la version 6 de Java, Sun client VM (je n'ai pas accès à d'autres versions). Le total de la différence de temps est de l'ordre de quelques millisecondes sur l'ensemble de test.
Par conséquent, la seule contrepartie est ce qui a l'air plus propre. Je trouve que la deuxième façon est moche, donc je m'en tiendrai à la première manière ou d' Ray Hayes façon.
Tandis que les performances pourraient être les mêmes et ce qui "ressemble" le mieux est très subjectif, il y a encore une assez grande différence dans les fonctionnalités. Prenons l'exemple suivant:
La boucle while est à l'intérieur du bloc try catch, la variable " j " est incrémenté jusqu'à ce qu'il frappe 40, imprimé quand j mod 4 est égal à zéro et qu'une exception est levée lorsque j hits 20.
Avant tout les détails, voici les autres exemple:
Même logique que ci-dessus, la seule différence est que le bloc try/catch est maintenant à l'intérieur de la boucle while.
Vient ici la sortie (alors que dans les try/catch):
Et l'autre sortie (try/catch en tout):
Là, vous avez tout à fait une différence importante:
tandis que dans le try/catch sauts hors de la boucle
try/catch dans tout garde la boucle active
try{} catch() {}
autour de la boucle si la boucle est considéré comme une seule "unité" et de trouver un problème dans cette unité rend l'ensemble de "l'unité" (ou boucle dans ce cas) aller dans le sud. Mettretry{} catch() {}
l'intérieur de la boucle si vous traitez une seule itération de la boucle, ou un seul élément dans un tableau d'ensemble de "l'unité". Si une exception dans ce "unité" se produit, nous avons simplement ignorer cet élément, puis nous continuons sur la prochaine itération de la boucle.Je suis d'accord avec toutes les performances et la lisibilité des messages. Cependant, il y a des cas où il n'a vraiment d'importance. Un couple d'autres personnes mentionnées, mais il pourrait être plus facile à voir avec des exemples.
Considérer cette légèrement modifiés exemple:
Si vous voulez le parseAll() permet de retourner la valeur null si il y a des erreurs (comme l'original exemple), vous auriez mis le try/catch sur l'extérieur comme ceci:
En réalité, vous devriez probablement retourner une erreur ici, au lieu de null, et généralement, je n'aime pas avoir plusieurs retours, mais vous obtenez l'idée.
D'autre part, si vous voulez qu'il suffit d'ignorer les problèmes, et d'analyser ce que les Chaînes c'est possible, vous auriez mis le try/catch à l'intérieur de la boucle comme ceci:
Comme déjà mentionné, la performance est la même. Toutefois, l'expérience utilisateur n'est pas nécessairement identiques. Dans le premier cas, vous allez échouer rapidement (c'est à dire après la première erreur), mais si vous mettez le bloc try/catch à l'intérieur de la boucle, vous pouvez capturer toutes les erreurs qui auraient pu être créés pour un appel à la méthode. Lors de l'analyse d'un tableau de valeurs à partir de chaînes où vous attendent quelques erreurs de mise en forme, il y a certainement des cas où vous aimeriez être en mesure de présenter toutes les erreurs de l'utilisateur, de sorte qu'ils n'ont pas besoin d'essayer de les résoudre un par un.
Si ses un tout-ou-rien échoue, le premier format de sens. Si vous voulez être en mesure de retourner tous les non-à défaut d'éléments, vous devez utiliser la deuxième forme. Ceux qui seraient mes critères de base pour choisir entre les méthodes. Personnellement, si c'est tout ou rien, je ne voudrais pas utiliser la deuxième forme.
Tant que vous êtes conscient de ce que vous devez accomplir dans la boucle que vous pourriez mettre le try catch en dehors de la boucle. Mais il est important de comprendre que la boucle sera alors fin dès que l'exception se produit et qui peut ne pas toujours être ce que vous voulez. C'est en fait une erreur très commune en Java basée sur le logiciel. Les gens ont besoin pour traiter un certain nombre d'éléments, tels que la vidange d'une file d'attente, à tort de compter sur un extérieur instruction try/catch de la manipulation de toutes les exceptions possibles. Ils pourraient aussi être la gestion d'une exception spécifique à l'intérieur de la boucle et ne pas attendre de toute autre exception à se produire.
Alors si une exception se produit qui n'est pas traitée à l'intérieur de la boucle et la boucle sera "preemted", elle se termine éventuellement prématurément et à l'extérieur instruction catch gère l'exception.
Si la boucle a aussi son rôle dans la vie de vider une file d'attente alors que la boucle que très probablement pourrait se terminer avant que la file d'attente n'a vraiment vidé. Très commune de la faute.
Dans votre exemple il n'y a pas de différence fonctionnelle. Je trouve ton premier exemple plus lisible.
Vous devriez préférer l'extérieur de version sur l'intérieure de la version. C'est juste une version spécifique de la règle, déplacer quoi que ce soit à l'extérieur de la boucle que vous pouvez déplacer à l'extérieur de la boucle. Selon l'IL et d'un compilateur compilateur JIT vos deux versions peuvent ou peuvent ne pas se retrouver avec des caractéristiques de performance différentes.
Sur une autre note, vous devriez probablement regarder flotter.TryParse ou Convertir.ToFloat.
Si vous mettez le try/catch à l'intérieur de la boucle, vous allez continuer boucle après qu'une exception. Si vous le mettez dehors de la boucle, vous allez vous arrêter dès qu'une exception est levée.
Mon point de vue serait de blocs try/catch sont nécessaires pour assurer la bonne gestion des exceptions, mais la création de ces blocs a des implications sur les performances. Depuis, les Boucles contiennent intensive répétitif des calculs, il n'est pas recommandé de mettre les blocs try/catch à l'intérieur des boucles. En outre, il semble que lorsque cette condition se produit, c'est souvent "Exception" ou "RuntimeException" qui est pris. RuntimeException d'être pris dans le code devrait être évitée. Encore une fois, si vous travaillez dans une grande entreprise, il est essentiel de journal d'exception correctement, ou arrêter l'exécution exception à arriver. Tout l'intérêt de cette description est
PLEASE AVOID USING TRY-CATCH BLOCKS IN LOOPS
paramètre en place un cadre de pile pour le try/catch ajoute une charge supplémentaire, mais la JVM peut être capable de détecter le fait que vous êtes de retour et d'optimiser cette distance.
en fonction du nombre d'itérations, de différence de performances devraient être négligeables.
Cependant je suis d'accord avec les autres que de l'avoir à l'extérieur de la boucle de rendre le corps de la boucle look plus propre.
Si il ya une chance que vous aurez jamais envie de continuer avec le traitement plutôt que de le quitter si il y a un nombre non valide, alors vous voulez le code à l'intérieur de la boucle.
Si c'est à l'intérieur, alors vous aurez des frais indirects de la try/catch structure N fois, en opposition à la fois à l'extérieur.
Chaque fois qu'un Try/Catch structure est appelée, elle ajoute de la surcharge à l'exécution de la méthode. Juste le petit peu de mémoire & processeur tiques nécessaires pour faire face à la structure. Si vous êtes en cours d'exécution d'une boucle 100 fois, et pour le hypothétique souci, disons-le coût est de 1 tick par try/catch appel, puis d'avoir le Try/Catch à l'intérieur de la boucle de vous coûte 100 tiques, contre seulement 1 cochez si c'est en dehors de la boucle.
Le point de l'ensemble des exceptions est d'encourager le premier style: laisser l'erreur de manipulation d'être consolidés et traitées une fois, pas tout de suite à toutes les erreurs possibles du site.
mettre à l'intérieur. Vous pouvez garder traitement (si vous voulez) ou vous pouvez jeter un utile exception qui indique au client la valeur de myString et l'index du tableau contenant les mauvaises valeur. Je pense que NumberFormatException déjà vous dire la mauvaise valeur, mais le principe est de placer toutes les données utiles dans les exceptions que vous jetez. Pensez à ce qui pourrait être intéressant pour vous dans le débogueur à ce point dans le programme.
Considérer:
Dans le temps de besoin, vous apprécierez vraiment une exception comme celle-ci avec autant d'informations que possible.
Je tiens à ajouter ma propre
0.02c
sur deux considérations concurrentes lorsque l'on regarde le problème général du où la position de la gestion des exceptions:La "grande" de la responsabilité de l'
try-catch
bloc (c'est à dire en dehors de la boucle dans votre cas) signifie que lorsque l'on modifie le code à un moment plus tard, vous pouvez, à tort, ajouter une ligne qui est géré par votrecatch
bloc; peut-être involontairement. Dans votre cas, c'est moins probable parce que vous êtes explicitement attraper unNumberFormatException
Le "plus étroite" de la responsabilité de l'
try-catch
bloc, le plus difficile refactoring devient. Surtout quand (comme dans votre cas), vous êtes à l'exécution d'un "non-local" de l'enseignement de l'intérieur de lacatch
bloc (lereturn null
déclaration).Qui dépend de l'échec de la manipulation. Si vous voulez juste pour ignorer l'erreur des éléments, essayez de l'intérieur:
Dans tous les autres cas, je préfère l'essayer dehors. Le code est plus lisible, il est plus propre. Il serait peut-être mieux de jeter une IllegalArgumentException dans le cas d'erreur si au lieu de retourner la valeur null.
Je vais mettre mon 0.02$. Parfois, vous finissez par avoir besoin d'ajouter un "enfin" plus tard dans votre code (car qui a jamais écrit leur code parfaitement la première fois?). Dans ces cas, tout à coup, il est plus logique d'avoir le try/catch en dehors de la boucle. Par exemple:
Parce que si vous obtenez une erreur, ou pas, vous ne voulez libérer votre connexion de base de données (ou choisissez votre type préféré d'autres ressources...) une fois.
Un autre aspect à ne pas mentionné dans le ci-dessus est le fait que chaque try-catch a certains impact sur la pile, ce qui peut avoir des implications pour les méthodes.
Si la méthode "externe (de)" les appels de méthode "interne()" (ce qui peut s'appeler lui-même de manière récursive), essayez de localiser le try-catch dans la méthode "externe (de)" si possible. Une simple pile "crash" exemple, nous allons utiliser dans une classe de performance échoue à environ 6 400 cadres lorsque le try-catch est dans l'intérieur de la méthode, et à peu près de 11 600 quand il est dans la méthode extérieure.
Dans le monde réel, cela peut être un problème si vous utilisez le diagramme Composite et possèdent de grands complexes de structures imbriquées.
Si vous voulez attraper l'Exception pour chaque itération, ou de vérifier à quel itération Exception est levée et attraper toutes les Exceptions dans un itertaion, place de try...catch à l'intérieur de la boucle. Ce ne sera pas briser la boucle si une Exception se produit et vous pouvez prendre tous les une Exception à chaque itération à travers la boucle.
Si vous voulez briser la boucle et d'examiner l'Exception chaque fois lancée, l'utilisation de try...catch hors de la boucle. Cela permettra de briser la boucle et d'exécuter des instructions après la capture (le cas échéant).
Tout dépend de votre besoin. Je préfère l'utilisation de try...catch à l'intérieur de la boucle, tandis que le déploiement de que, si une Exception se produit, les résultats ne sont pas ambigus et la boucle ne sera pas briser et de les exécuter complètement.