Question: La gestion des exceptions en Java est-elle réellement lente?
La sagesse conventionnelle, ainsi que de nombreux résultats de Google, disent qu'une logique exceptionnelle ne doit pas être utilisée pour un flux de programme normal en Java. Deux raisons sont généralement données,
- il est vraiment lent - même un ordre de grandeur plus lent que le code normal (les raisons données varient),
et
- c'est désordonné car les gens s'attendent à ce que seules les erreurs soient traitées dans un code exceptionnel.
Cette question porte sur # 1.
À titre d'exemple, cette page décrit la gestion des exceptions Java comme «très lente» et met en relation la lenteur avec la création de la chaîne de message d'exception - «cette chaîne est ensuite utilisée pour créer l'objet d'exception qui est levé. Ce n'est pas rapide». L'article sur la gestion efficace des exceptions en Java indique que "la raison en est due à l'aspect de création d'objet de la gestion des exceptions, ce qui rend par conséquent le lancement d'exceptions intrinsèquement lent". Une autre raison est que la génération de trace de pile est ce qui la ralentit.
Mes tests (en utilisant Java 1.6.0_07, Java HotSpot 10.0, sur Linux 32 bits), indiquent que la gestion des exceptions n'est pas plus lente que le code normal. J'ai essayé d'exécuter une méthode dans une boucle qui exécute du code. À la fin de la méthode, j'utilise un booléen pour indiquer s'il faut retourner ou lancer . De cette façon, le traitement réel est le même. J'ai essayé d'exécuter les méthodes dans des ordres différents et de faire la moyenne de mes temps de test, pensant qu'il s'agissait peut-être de l'échauffement de la JVM. Dans tous mes tests, le lancer a été au moins aussi rapide que le retour, sinon plus rapide (jusqu'à 3,1% plus rapide). Je suis complètement ouvert à la possibilité que mes tests aient été incorrects, mais je n'ai rien vu sur le chemin de l'exemple de code, des comparaisons de tests ou des résultats au cours des deux dernières années qui montrent que la gestion des exceptions en Java est réellement lent.
Ce qui m'amène dans cette voie, c'est une API que je devais utiliser et qui lançait des exceptions dans le cadre de la logique de contrôle normale. Je voulais les corriger dans leur utilisation, mais maintenant je ne peux peut-être pas le faire. Dois-je plutôt les féliciter pour leur réflexion prospective?
Dans l'article Gestion efficace des exceptions Java dans la compilation juste à temps , les auteurs suggèrent que la présence de gestionnaires d'exceptions seuls, même si aucune exception n'est levée, est suffisante pour empêcher le compilateur JIT d'optimiser correctement le code, le ralentissant ainsi . Je n'ai pas encore testé cette théorie.
la source
exceptions are, as their name implies, to be used only for exceptional conditions; they should never be used for ordinary control flow
- en donnant une explication complète et détaillée des raisons. Et c'est lui qui a écrit Java lib. C'est donc lui qui définit le contrat d'API des classes. / Je suis d'accord avec Bill K sur celui-ci.Réponses:
Cela dépend de la façon dont les exceptions sont implémentées. La manière la plus simple est d'utiliser setjmp et longjmp. Cela signifie que tous les registres du CPU sont écrits dans la pile (ce qui prend déjà un certain temps) et éventuellement d'autres données doivent être créées ... tout cela se produit déjà dans l'instruction try. L'instruction throw doit dérouler la pile et restaurer les valeurs de tous les registres (et éventuellement d'autres valeurs dans la machine virtuelle). Donc, try et throw sont également lents, ce qui est assez lent, mais si aucune exception n'est levée, la sortie du bloc try ne prend aucun temps dans la plupart des cas (car tout est placé sur la pile qui se nettoie automatiquement si la méthode existe).
Sun et d'autres ont reconnu que cela est peut-être sous-optimal et bien sûr les machines virtuelles deviennent de plus en plus rapides au fil du temps. Il existe une autre façon d'implémenter des exceptions, ce qui rend l'essai lui-même rapide comme l'éclair (en fait, rien ne se passe pour essayer du tout en général - tout ce qui doit se produire est déjà fait lorsque la classe est chargée par la machine virtuelle) et cela rend le lancer pas aussi lent . Je ne sais pas quelle JVM utilise cette nouvelle et meilleure technique ...
... mais écrivez-vous en Java afin que votre code ne s'exécute plus tard que sur une seule machine virtuelle Java sur un système spécifique? Étant donné que si elle peut jamais fonctionner sur une autre plate-forme ou toute autre version JVM (éventuellement d'un autre fournisseur), qui dit qu'ils utilisent également l'implémentation rapide? Le rapide est plus compliqué que le lent et n'est pas facilement possible sur tous les systèmes. Vous voulez rester portable? Alors ne comptez pas sur les exceptions rapides.
Cela fait également une grande différence ce que vous faites dans un bloc d'essai. Si vous ouvrez un bloc try et n'appelez jamais aucune méthode à partir de ce bloc try, le bloc try sera ultra rapide, car le JIT peut alors traiter un lancer comme un simple goto. Il n'a pas besoin de sauvegarder l'état de la pile ni de dérouler la pile si une exception est levée (il suffit de passer aux gestionnaires de capture). Cependant, ce n'est pas ce que vous faites habituellement. Habituellement, vous ouvrez un bloc try et appelez ensuite une méthode qui pourrait lever une exception, non? Et même si vous utilisez simplement le bloc try dans votre méthode, de quel type de méthode s'agit-il, qui n'appelle aucune autre méthode? Va-t-il simplement calculer un nombre? Alors pourquoi avez-vous besoin d'exceptions? Il existe des moyens beaucoup plus élégants de réguler le flux des programmes. Pour à peu près tout autre chose que des mathématiques simples,
Voir le code de test suivant:
Résultat:
Le ralentissement du bloc try est trop faible pour exclure les facteurs de confusion tels que les processus d'arrière-plan. Mais le bloc de capture a tout tué et a ralenti 66 fois!
Comme je l'ai dit, le résultat ne sera pas si mauvais si vous mettez try / catch et throw all dans la même méthode (method3), mais c'est une optimisation JIT spéciale sur laquelle je ne me fierais pas. Et même en utilisant cette optimisation, le lancer est encore assez lent. Je ne sais donc pas ce que vous essayez de faire ici, mais il y a certainement une meilleure façon de le faire que d'utiliser try / catch / throw.
la source
nanoTime()
nécessite Java 1.5 et je n'avais que Java 1.4 disponible sur le système que j'ai utilisé pour écrire le code ci-dessus. De plus, cela ne joue pas un rôle énorme dans la pratique. La seule différence entre les deux est que l'une est nanoseconde l'autre millisecondes etnanoTime
n'est pas influencée par les manipulations d'horloge (qui ne sont pas pertinentes, sauf si vous ou le processus système modifiez l'horloge système exactement au moment où le code de test s'exécute). En règle générale, vous avez raison, biennanoTime
sûr , est le meilleur choix.try
bloc, mais nonthrow
. Votrethrow
test est levée des exceptions 50% du temps il passe par latry
. C'est clairement une situation où l'échec n'est pas exceptionnel . Le réduire à seulement 10% réduit massivement les performances. Le problème avec ce type de test est qu'il encourage les gens à cesser complètement d'utiliser les exceptions. L'utilisation d'exceptions, pour une gestion exceptionnelle des cas, fonctionne bien mieux que ce que montre votre test.return
. Il laisse une méthode quelque part au milieu du corps, peut-être même au milieu d'une opération (qui n'a jusqu'à présent été complétée que de 50%) et lecatch
bloc peut contenir 20 images de pile vers le haut (une méthode a untry
bloc, appelant la méthode 1, qui appelle method2, qui appelle mehtod3, ..., et dans method20 au milieu d'une opération, une exception est levée). La pile doit être déroulée de 20 images vers le haut, toutes les opérations inachevées doivent être annulées (les opérations ne doivent pas être à moitié effectuées) et les registres du processeur doivent être dans un état propre. Tout cela prend du temps.Pour info, j'ai prolongé l'expérience de Mecki:
Les 3 premiers sont les mêmes que ceux de Mecki (mon ordinateur portable est évidemment plus lent).
La méthode 4 est identique à la méthode 3, sauf qu'elle crée un
new Integer(1)
plutôt que de le fairethrow new Exception()
.method5 est comme method3 sauf qu'il crée le
new Exception()
sans le lancer.method6 est similaire à method3, sauf qu'il lève une exception pré-créée (une variable d'instance) plutôt que d'en créer une nouvelle.
En Java, une grande partie des dépenses liées au lancement d'une exception est le temps passé à collecter la trace de pile, qui se produit lorsque l'objet d'exception est créé. Le coût réel de levée de l'exception, bien qu'il soit important, est considérablement inférieur au coût de création de l'exception.
la source
Aleksey Shipilëv a fait une analyse très approfondie dans laquelle il compare les exceptions Java dans diverses combinaisons de conditions:
Il les compare également aux performances de vérification d'un code d'erreur à différents niveaux de fréquence d'erreur.
Les conclusions (citées mot pour mot de son message) étaient les suivantes:
Les exceptions vraiment exceptionnelles sont magnifiquement performantes. Si vous les utilisez comme prévu et ne communiquez les cas vraiment exceptionnels qu'au nombre écrasant de cas non exceptionnels traités par du code normal, alors l'utilisation d'exceptions est la meilleure performance.
Les coûts de performance des exceptions ont deux composants principaux: la construction de la trace de la pile lorsque l'exception est instanciée et le déroulement de la pile pendant le lancement de l'exception.
Les coûts de construction des traces de pile sont proportionnels à la profondeur de la pile au moment de l'instanciation d'exception. C'est déjà mauvais parce que qui sur Terre connaît la profondeur de la pile à laquelle cette méthode de lancement serait appelée? Même si vous désactivez la génération de trace de pile et / ou mettez en cache les exceptions, vous ne pouvez vous débarrasser que de cette partie du coût des performances.
Les coûts de déroulement de la pile dépendent de la chance que nous avons de rapprocher le gestionnaire d'exceptions dans le code compilé. Structurer soigneusement le code pour éviter une recherche approfondie de gestionnaires d'exceptions nous aide probablement à avoir plus de chance.
Si nous éliminons les deux effets, le coût de performance des exceptions est celui de la branche locale. Peu importe sa beauté, cela ne signifie pas que vous devez utiliser Exceptions comme flux de contrôle habituel, car dans ce cas, vous êtes à la merci d'optimiser le compilateur! Vous ne devez les utiliser que dans des cas vraiment exceptionnels, où la fréquence des exceptions amortit le coût malchanceux possible de la levée de l'exception réelle.
La règle empirique optimiste semble être une fréquence de 10 ^ -4 pour les exceptions, ce qui est assez exceptionnel. Cela, bien sûr, dépend des poids lourds des exceptions elles-mêmes, des actions exactes prises dans les gestionnaires d'exceptions, etc.
Le résultat est que lorsqu'une exception n'est pas levée, vous ne payez pas de frais, donc lorsque la condition exceptionnelle est suffisamment rare, la gestion des exceptions est plus rapide que l'utilisation à
if
chaque fois. Le post complet vaut vraiment la peine d'être lu.la source
Malheureusement, ma réponse est trop longue pour être publiée ici. Alors permettez-moi de résumer ici et de vous référer à http://www.fuwjax.com/how-slow-are-java-exceptions/ pour les détails concrets.
La vraie question ici n'est pas "Quelle est la lenteur des" échecs signalés comme exceptions "par rapport au" code qui n'échoue jamais "?" comme la réponse acceptée pourrait vous le faire croire. Au lieu de cela, la question devrait être "Quelle est la lenteur des" échecs signalés en tant qu'exceptions "par rapport aux échecs signalés par d'autres moyens?" Généralement, les deux autres façons de signaler les échecs sont soit avec des valeurs sentinelles, soit avec des wrappers de résultats.
Les valeurs sentinelles sont une tentative de renvoyer une classe en cas de succès et une autre en cas d'échec. Vous pouvez y penser presque comme renvoyant une exception au lieu d'en lancer une. Cela nécessite une classe parent partagée avec l'objet de réussite, puis une vérification "instanceof" et quelques transtypages pour obtenir les informations de réussite ou d'échec.
Il se trouve qu'au risque de sécurité de type, les valeurs Sentinel sont plus rapides que les exceptions, mais seulement d'un facteur d'environ 2x. Maintenant, cela peut sembler beaucoup, mais ce 2x ne couvre que le coût de la différence de mise en œuvre. En pratique, le facteur est beaucoup plus faible car nos méthodes qui pourraient échouer sont beaucoup plus intéressantes que quelques opérateurs arithmétiques comme dans l'exemple de code ailleurs dans cette page.
Les enveloppes de résultat, d'autre part, ne sacrifient pas du tout la sécurité du type. Ils regroupent les informations de réussite et d'échec dans une seule classe. Ainsi, au lieu de "instanceof", ils fournissent un "isSuccess ()" et des getters pour les objets de réussite et d'échec. Cependant, les objets de résultat sont environ 2 fois plus lents que l'utilisation d'exceptions. Il s'avère que créer un nouvel objet wrapper à chaque fois est beaucoup plus cher que de lancer une exception parfois.
En plus de cela, le langage fourni permet d'indiquer qu'une méthode peut échouer. Il n'y a pas d'autre moyen de savoir à partir de l'API uniquement les méthodes qui devraient toujours (principalement) fonctionner et celles qui devraient signaler un échec.
Les exceptions sont plus sûres que les sentinelles, plus rapides que les objets résultants et moins surprenantes que les deux. Je ne suggère pas que try / catch remplace if / else, mais les exceptions sont le bon moyen de signaler un échec, même dans la logique métier.
Cela dit, je voudrais souligner que les deux moyens les plus fréquents d'influer considérablement sur les performances que j'ai rencontrés sont la création d'objets inutiles et de boucles imbriquées. Si vous avez le choix entre créer une exception ou ne pas créer d'exception, ne créez pas l'exception. Si vous avez le choix entre créer une exception parfois ou créer un autre objet tout le temps, créez l'exception.
la source
J'ai étendu les réponses données par @Mecki et @incarnate , sans remplissage stacktrace pour Java.
Avec Java 7+, nous pouvons utiliser
Throwable(String message, Throwable cause, boolean enableSuppression,boolean writableStackTrace)
. Mais pour Java6, voir ma réponse à cette questionSortie avec Java 1.6.0_45, sur Core i7, 8 Go de RAM:
Ainsi, les méthodes qui retournent des valeurs sont toujours plus rapides que les méthodes qui génèrent des exceptions. À mon humble avis, nous ne pouvons pas concevoir une API claire en utilisant simplement des types de retour pour les flux de réussite et d'erreur. Les méthodes qui génèrent des exceptions sans stacktrace sont 4 à 5 fois plus rapides que les exceptions normales.
Edit: NoStackTraceThrowable.java Merci @Greg
la source
public class NoStackTraceThrowable extends Throwable { public NoStackTraceThrowable() { super("my special throwable", null, false, false); } }
With Java 7+, we can use
mais plus tard vous avez écrit c'estOutput with Java 1.6.0_45,
donc le résultat Java 6 ou 7Throwable
constructeur qui aboolean writableStackTrace
arg. Mais cela n'est pas présent dans Java 6 et inférieur. C'est pourquoi j'ai donné une implémentation personnalisée pour Java 6 et inférieur. Le code ci-dessus est donc pour Java 6 et inférieur. Veuillez lire attentivement la 1ère ligne du 2ème para.Optional
ou similaire est arrivé un peu tard à Java. Avant cela, nous utilisions également des objets wrapper avec des indicateurs de réussite / d'erreur. Mais cela semble être un peu hacks et ne me semble pas naturel.Il y a quelque temps, j'ai écrit une classe pour tester les performances relatives de la conversion de chaînes en entiers en utilisant deux approches: (1) appeler Integer.parseInt () et intercepter l'exception, ou (2) faire correspondre la chaîne avec une expression régulière et appeler parseInt () seulement si le match réussit. J'ai utilisé l'expression régulière de la manière la plus efficace possible (c'est-à-dire en créant les objets Pattern et Matcher avant d'intervenir dans la boucle), et je n'ai pas imprimé ou enregistré les traces de pile des exceptions.
Pour une liste de dix mille chaînes, s'il s'agissait de nombres valides, l'approche parseInt () était quatre fois plus rapide que l'approche regex. Mais si seulement 80% des chaînes étaient valides, l'expression régulière était deux fois plus rapide que parseInt (). Et si 20% étaient valides, ce qui signifie que l'exception a été levée et interceptée 80% du temps, l'expression régulière était environ vingt fois plus rapide que parseInt ().
J'ai été surpris par le résultat, étant donné que l'approche regex traite deux fois des chaînes valides: une fois pour la correspondance et de nouveau pour parseInt (). Mais lever et attraper des exceptions a plus que compensé cela. Ce genre de situation n'est pas susceptible de se produire très souvent dans le monde réel, mais si c'est le cas, vous ne devriez certainement pas utiliser la technique de capture d'exception. Mais si vous ne validez que les entrées utilisateur ou quelque chose comme ça, utilisez certainement l'approche parseInt ().
la source
Integer.ParseInt()
) et je m'attends à ce que la plupart du temps, l'entrée utilisateur soit correcte, donc pour mon cas d'utilisation, il semble que la prise de l'exception occasionnelle soit la voie à suivre .Je pense que le premier article fait référence à l'acte de traverser la pile d'appels et de créer une trace de pile comme étant la partie coûteuse, et bien que le deuxième article ne le dise pas, je pense que c'est la partie la plus coûteuse de la création d'objets. John Rose a un article où il décrit différentes techniques pour accélérer les exceptions . (Préallocation et réutilisation d'une exception, exceptions sans traces de pile, etc.)
Mais encore - je pense que cela ne devrait être considéré que comme un mal nécessaire, un dernier recours. La raison pour laquelle John fait cela est d'émuler des fonctionnalités dans d'autres langues qui ne sont pas (encore) disponibles dans la JVM. Vous ne devez PAS prendre l'habitude d'utiliser des exceptions pour le flux de contrôle. Surtout pas pour des raisons de performances! Comme vous le mentionnez vous-même au # 2, vous risquez de masquer de graves bogues dans votre code de cette manière, et il sera plus difficile à maintenir pour les nouveaux programmeurs.
Les microbenchmarks en Java sont étonnamment difficiles à obtenir correctement (on m'a dit), surtout lorsque vous entrez en territoire JIT, donc je doute vraiment que l'utilisation des exceptions soit plus rapide que le "retour" dans la vie réelle. Par exemple, je suppose que vous avez entre 2 et 5 cadres de pile dans votre test? Imaginez maintenant que votre code sera invoqué par un composant JSF déployé par JBoss. Vous pouvez maintenant avoir une trace de pile de plusieurs pages.
Peut-être pourriez-vous publier votre code de test?
la source
Je ne sais pas si ces sujets se rapportent, mais j'ai voulu implémenter une astuce en se basant sur la trace de la pile du thread actuel: je voulais découvrir le nom de la méthode, qui a déclenché l'instanciation à l'intérieur de la classe instanciée (oui, l'idée est folle, Je l'ai totalement abandonné). J'ai donc découvert que l'appel
Thread.currentThread().getStackTrace()
est extrêmement lent (en raison de ladumpThreads
méthode native qu'il utilise en interne).Java
Throwable
a donc une méthode nativefillInStackTrace
. Je pense que le killer-catch
block décrit plus haut déclenche en quelque sorte l'exécution de cette méthode.Mais laissez-moi vous raconter une autre histoire ...
Dans Scala, certaines fonctionnalités sont compilées dans JVM à l'aide de
ControlThrowable
, ce qui étendThrowable
et remplace sonfillInStackTrace
de la manière suivante:J'ai donc adapté le test ci-dessus (le nombre de cycles est diminué de dix, ma machine est un peu plus lente :):
Les résultats sont donc:
Vous voyez, la seule différence entre
method3
etmethod4
est qu'ils lèvent différents types d'exceptions. Yeap,method4
est toujours plus lent quemethod1
etmethod2
, mais la différence est beaucoup plus acceptable.la source
J'ai fait des tests de performances avec JVM 1.5 et l'utilisation des exceptions était au moins 2x plus lente. En moyenne: le temps d'exécution sur une méthode trivialement petite a plus que triplé (3x) avec des exceptions. Une boucle trivialement petite qui devait rattraper l'exception a vu une augmentation de 2x du temps libre.
J'ai vu des chiffres similaires dans le code de production ainsi que des micro-repères.
Les exceptions ne doivent certainement PAS être utilisées pour tout ce qui est appelé fréquemment. Lancer des milliers d'exceptions par seconde provoquerait un énorme goulot d'étranglement.
Par exemple, utiliser "Integer.ParseInt (...)" pour trouver toutes les mauvaises valeurs dans un très gros fichier texte - très mauvaise idée. (J'ai vu cette méthode utilitaire tuer les performances sur le code de production)
Utilisation d'une exception pour signaler une mauvaise valeur sur un formulaire GUI utilisateur, probablement pas si mauvaise du point de vue des performances.
Que ce soit une bonne pratique de conception ou non, j'opterais pour la règle: si l'erreur est normale / attendue, utilisez une valeur de retour. Si c'est anormal, utilisez une exception. Par exemple: lors de la lecture des entrées utilisateur, les mauvaises valeurs sont normales - utilisez un code d'erreur. En passant une valeur à une fonction utilitaire interne, les mauvaises valeurs doivent être filtrées en appelant du code - utilisez une exception.
la source
Des performances exceptionnelles en Java et en C # laissent beaucoup à désirer.
En tant que programmeurs, cela nous oblige à respecter la règle "les exceptions doivent être occasionnelles", simplement pour des raisons pratiques de performances.
Cependant, en tant qu'informaticiens, nous devons nous rebeller contre cet état problématique. La personne qui crée une fonction n'a souvent aucune idée de la fréquence à laquelle elle sera appelée, ni si le succès ou l'échec est plus probable. Seul l'appelant dispose de ces informations. Essayer d'éviter les exceptions conduit à des idoms d'API peu clairs où, dans certains cas, nous n'avons que des versions d'exception propres mais lentes, et dans d'autres cas, nous avons des erreurs de valeur de retour rapides mais maladroites, et dans d'autres cas nous nous retrouvons avec les deux . Le réalisateur de la bibliothèque peut devoir écrire et maintenir deux versions d'API, et l'appelant doit décider laquelle des deux versions utiliser dans chaque situation.
C'est une sorte de gâchis. Si les exceptions avaient de meilleures performances, nous pourrions éviter ces idiomes maladroits et utiliser les exceptions telles qu'elles étaient censées être utilisées ... comme une fonction de retour d'erreur structurée.
J'aimerais vraiment voir des mécanismes d'exception implémentés en utilisant des techniques plus proches des valeurs de retour, afin que nous puissions avoir des performances plus proches des valeurs de retour .. puisque c'est ce à quoi nous revenons dans un code sensible aux performances.
Voici un exemple de code qui compare les performances d'exception aux performances de valeur de retour d'erreur.
classe public TestIt {
}
Et voici les résultats:
La vérification et la propagation des valeurs de retour ajoutent un coût par rapport à l'appel de référence nulle, et ce coût est proportionnel à la profondeur des appels. À une profondeur de chaîne d'appels de 8, la version de vérification de la valeur de retour d'erreur était environ 27% plus lente que la version de base qui ne vérifiait pas les valeurs de retour.
Les performances d'exception, en comparaison, ne sont pas fonction de la profondeur d'appel, mais de la fréquence des exceptions. Cependant, la dégrédation lorsque la fréquence des exceptions augmente est beaucoup plus dramatique. À seulement une fréquence d'erreur de 25%, le code s'exécutait 24 fois plus lentement. À une fréquence d'erreur de 100%, la version d'exception est presque 100 fois plus lente.
Cela me suggère que peut-être font les mauvais compromis dans nos implémentations d'exception. Les exceptions pourraient être plus rapides, soit en évitant des trajets coûteux, soit en les transformant carrément en vérification de la valeur de retour prise en charge par le compilateur. Jusqu'à ce qu'ils le fassent, nous sommes bloqués en les évitant lorsque nous voulons que notre code s'exécute rapidement.
la source
HotSpot est tout à fait capable de supprimer le code d'exception pour les exceptions générées par le système, tant qu'il est tout en ligne. Cependant, les exceptions créées explicitement et celles qui ne sont pas supprimées autrement passent beaucoup de temps à créer la trace de la pile. Remplacez
fillInStackTrace
pour voir comment cela peut affecter les performances.la source
Même si lever une exception n'est pas lent, c'est toujours une mauvaise idée de lever des exceptions pour un flux de programme normal. Utilisé de cette façon, il est analogue à un GOTO ...
Je suppose que cela ne répond pas vraiment à la question. J'imagine que la sagesse «conventionnelle» de lancer des exceptions lentement était vraie dans les versions java antérieures (<1.4). La création d'une exception nécessite que la machine virtuelle crée la trace de pile complète. Beaucoup de choses ont changé depuis lors dans la machine virtuelle pour accélérer les choses et c'est probablement un domaine qui a été amélioré.
la source
break
oureturn
pas ungoto
.Comparez simplement, disons Integer.parseInt à la méthode suivante, qui retourne simplement une valeur par défaut dans le cas de données non analysables au lieu de lever une exception:
Tant que vous appliquez les deux méthodes à des données "valides", elles fonctionneront toutes les deux à peu près au même rythme (même si Integer.parseInt parvient à gérer des données plus complexes). Mais dès que vous essayez d'analyser des données invalides (par exemple pour analyser "abc" 1.000.000 fois), la différence de performances devrait être essentielle.
la source
Un excellent article sur les performances des exceptions est:
https://shipilev.net/blog/2014/exceptional-performance/
Instanciation vs réutilisation existante, avec trace de pile et sans, etc:
Selon la profondeur de la trace de la pile:
Pour d'autres détails (y compris l'assembleur x64 de JIT), lisez l'article de blog original.
Cela signifie que Hibernate / Spring / etc-EE-shit sont lents en raison des exceptions (xD) et de la réécriture du flux de contrôle des applications loin des exceptions (remplacez-le par
continure
/break
et retournez desboolean
indicateurs comme en C à partir de l'appel de méthode) améliorez les performances de votre application 10x-100x , selon la fréquence à laquelle vous les lancez))la source
J'ai changé la réponse de @Mecki ci-dessus pour que method1 retourne un booléen et une vérification dans la méthode d'appel, car vous ne pouvez pas simplement remplacer une exception par rien. Après deux exécutions, la méthode1 était toujours la plus rapide ou aussi rapide que la méthode2.
Voici un aperçu du code:
et résultats:
Exécuter 1
Exécuter 2
la source
Une exception est destinée à gérer des conditions inattendues au moment de l'exécution uniquement.
L'utilisation d'une exception à la place d'une simple validation qui peut être effectuée au moment de la compilation retardera la validation jusqu'au moment de l'exécution. Cela réduira à son tour l'efficacité du programme.
Lancer une exception au lieu d'utiliser une simple validation if..else rendra également le code complexe à écrire et à maintenir.
la source
Mon avis sur la vitesse d'exception par rapport à la vérification des données par programme.
De nombreuses classes avaient un convertisseur de chaîne en valeur (scanner / analyseur), des bibliothèques respectées et bien connues;)
a généralement une forme
le nom d'exception n'est qu'un exemple, n'est généralement pas coché (runtime), donc la déclaration throws n'est que ma photo
existent parfois une deuxième forme:
ne jamais jeter
Lorsque le second n'est pas disponible (ou que le programmeur lit trop de documents et n'utilise que le premier), écrivez ce code avec une expression régulière. Les expressions régulières sont cool, politiquement correctes etc:
avec ce code les programmeurs n'ont pas coûté d'exceptions. MAIS A TOUJOURS un coût comparable très élevé d'expressions régulières par rapport à un petit coût d'exception parfois.
J'utilise presque toujours dans un tel contexte
sans analyser stacktrace etc, je crois qu'après des cours de vôtre assez rapides.
N'ayez pas peur Exceptions
la source
Pourquoi les exceptions devraient-elles être plus lentes que les retours normaux?
Tant que vous n'imprimez pas le stacktrace sur le terminal, l'enregistrez dans un fichier ou quelque chose de similaire, le catch-block ne fait pas plus de travail que les autres blocs de code. Donc, je ne peux pas imaginer pourquoi "throw new my_cool_error ()" devrait être si lent.
Bonne question et j'ai hâte d'avoir plus d'informations sur ce sujet!
la source