Quels sont des exemples concrets pour comprendre le rôle clé des assertions?
java
assertions
Praveen
la source
la source
Réponses:
Les assertions (via le mot clé assert ) ont été ajoutées dans Java 1.4. Ils sont utilisés pour vérifier l'exactitude d'un invariant dans le code. Ils ne doivent jamais être déclenchés dans le code de production et indiquent un bogue ou une mauvaise utilisation d'un chemin de code. Ils peuvent être activés au moment de l'exécution au moyen de l'
-ea
option sur lejava
commande, mais ne sont pas activés par défaut.Un exemple:
la source
assert
pour vérifier les paramètres des méthodes publiques ( docs.oracle.com/javase/1.4.2/docs/guide/lang/assert.html ). Cela devrait jeter unException
au lieu de tuer le programme.This convention is unaffected by the addition of the assert construct. Do not use assertions to check the parameters of a public method. An assert is inappropriate because the method guarantees that it will always enforce the argument checks. It must check its arguments whether or not assertions are enabled. Further, the assert construct does not throw an exception of the specified type. It can throw only an AssertionError.
docs.oracle.com/javase/8/docs/technotes/guides/language/…Supposons que vous êtes censé écrire un programme pour contrôler une centrale nucléaire. Il est assez évident que même l'erreur la plus mineure pourrait avoir des résultats catastrophiques, donc votre code doit être exempt de bogues (en supposant que la JVM est exempte de bogues pour le bien de l'argument).
Java n'est pas un langage vérifiable, ce qui signifie: vous ne pouvez pas calculer que le résultat de votre opération sera parfait. La raison principale en est les pointeurs: ils peuvent pointer n'importe où ou nulle part, donc ils ne peuvent pas être calculés pour avoir cette valeur exacte, du moins pas dans une plage de code raisonnable. Compte tenu de ce problème, il n'y a aucun moyen de prouver que votre code est correct dans son ensemble. Mais ce que vous pouvez faire, c'est de prouver que vous trouvez au moins tous les bogues quand cela se produit.
Cette idée est basée sur le paradigme de la conception par contrat (DbC): vous définissez d'abord (avec une précision mathématique) ce que votre méthode est censée faire, puis vous le vérifiez en le testant lors de l'exécution réelle. Exemple:
Bien que cela soit assez évident pour fonctionner correctement, la plupart des programmeurs ne verront pas le bug caché à l'intérieur de celui-ci (indice: Ariane V s'est écrasé à cause d'un bug similaire). Maintenant, DbC définit que vous devez toujours vérifier l'entrée et la sortie d'une fonction pour vérifier qu'elle fonctionne correctement. Java peut le faire à travers des assertions:
Si cette fonction échoue maintenant, vous le remarquerez. Vous saurez qu'il y a un problème dans votre code, vous savez où il se trouve et vous savez ce qui l'a provoqué (similaire aux exceptions). Et ce qui est encore plus important: vous arrêtez de vous exécuter correctement quand cela arrive pour empêcher tout code supplémentaire de fonctionner avec des valeurs incorrectes et potentiellement endommager tout ce qu'il contrôle.
Les exceptions Java sont un concept similaire, mais elles ne parviennent pas à tout vérifier. Si vous voulez encore plus de contrôles (au prix de la vitesse d'exécution), vous devez utiliser des assertions. Cela gonflera votre code, mais vous pouvez finalement livrer un produit à un temps de développement étonnamment court (plus vous corrigez un bogue tôt, plus le coût est faible). Et en plus: s'il y a un bug dans votre code, vous le détecterez. Il n'y a aucun moyen de laisser passer un bogue et de provoquer des problèmes plus tard.
Ce n'est toujours pas une garantie pour un code sans bogue, mais c'est beaucoup plus proche de cela que les programmes habituels.
la source
new IllegalArgumentException
avec le message? Je veux dire, en plus d'avoir o ajouterthrows
à la déclaration de méthode et au code pour gérer cette exception ailleurs. Pourquoiassert
insetad de lancer une nouvelle exception? Ou pourquoi pas unif
au lieu deassert
? Je ne peux pas vraiment obtenir ça :(a
peut être négative. La deuxième affirmation est inutile; pour les valeurs int, il est toujours vrai que a + b - b == a. Ce test ne peut échouer que si l'ordinateur est fondamentalement cassé. Pour vous défendre contre cette éventualité, vous devez vérifier la cohérence entre plusieurs processeurs.Les assertions sont un outil en phase de développement pour détecter les bogues dans votre code. Ils sont conçus pour être facilement supprimés, ils n'existeront donc pas dans le code de production. Les assertions ne font donc pas partie de la «solution» que vous livrez au client. Ce sont des vérifications internes pour s'assurer que les hypothèses que vous faites sont correctes. L'exemple le plus courant consiste à tester null. De nombreuses méthodes sont écrites comme ceci:
Très souvent dans une méthode comme celle-ci, le widget ne doit tout simplement jamais être nul. Donc, s'il est nul, il y a un bogue dans votre code que vous devez rechercher. Mais le code ci-dessus ne vous le dira jamais. Donc, dans un effort bien intentionné pour écrire du code "sûr", vous cachez également un bogue. Il vaut mieux écrire du code comme ceci:
De cette façon, vous serez sûr d'attraper ce bug tôt. (Il est également utile de spécifier dans le contrat que ce paramètre ne doit jamais être nul.) Veillez à activer les assertions lorsque vous testez votre code pendant le développement. (Et persuader vos collègues de le faire aussi est souvent difficile, ce que je trouve très ennuyeux.)
Maintenant, certains de vos collègues s'opposeront à ce code, faisant valoir que vous devriez toujours mettre la vérification nulle pour empêcher une exception en production. Dans ce cas, l'assertion est toujours utile. Vous pouvez l'écrire comme ceci:
De cette façon, vos collègues seront heureux que le contrôle nul soit là pour le code de production, mais pendant le développement, vous ne cachez plus le bogue lorsque le widget est nul.
Voici un exemple concret: j'ai écrit une fois une méthode qui comparait deux valeurs arbitraires pour l'égalité, où l'une ou l'autre valeur pouvait être nulle:
Ce code délègue le travail de la
equals()
méthode dans le cas où thisValue n'est pas null. Mais il suppose que laequals()
méthode remplit correctement le contratequals()
en traitant correctement un paramètre nul.Un collègue s'est opposé à mon code, me disant que beaucoup de nos classes ont des
equals()
méthodes de bug qui ne testent pas null, donc je devrais mettre cette vérification dans cette méthode. C'est discutable si c'est sage, ou si nous devons forcer l'erreur, afin que nous puissions la repérer et la corriger, mais j'ai remis à mon collègue et mis une vérification nulle, que j'ai marquée avec un commentaire:La vérification supplémentaire ici,
other != null
n'est nécessaire que si laequals()
méthode ne parvient pas à vérifier la valeur null comme requis par son contrat.Plutôt que d'engager un débat infructueux avec mon collègue sur la sagesse de laisser le code buggy dans notre base de code, je mets simplement deux assertions dans le code. Ces assertions me permettront de savoir, pendant la phase de développement, si l'une de nos classes ne parvient pas à s'implémenter
equals()
correctement, donc je peux le corriger:Les points importants à garder à l'esprit sont les suivants:
Les assertions ne sont que des outils de phase de développement.
Le point d'une assertion est de vous faire savoir s'il y a un bug, pas seulement dans votre code, mais dans votre base de code . (Les assertions ici signaleront en fait des bogues dans d'autres classes.)
Même si mon collègue était convaincu que nos cours étaient correctement écrits, les affirmations ici seraient toujours utiles. De nouvelles classes seront ajoutées qui pourraient échouer à tester pour null, et cette méthode peut signaler ces bogues pour nous.
En cours de développement, vous devez toujours activer les assertions, même si le code que vous avez écrit n'utilise pas d'assertions. Mon IDE est configuré pour toujours le faire par défaut pour tout nouvel exécutable.
Les assertions ne changent pas le comportement du code en production, donc mon collègue est heureux que la vérification nulle soit là et que cette méthode s'exécute correctement même si la
equals()
méthode est boguée. Je suis content car j'attraperai n'importe quelleequals()
méthode de buggy en développement.En outre, vous devez tester votre stratégie d'assertion en insérant une assertion temporaire qui échouera, afin que vous puissiez être certain d'être averti, soit via le fichier journal, soit via une trace de pile dans le flux de sortie.
la source
Beaucoup de bonnes réponses expliquant ce que fait le
assert
mot-clé, mais peu de réponses à la vraie question, "quand leassert
mot - clé devrait -il être utilisé dans la vraie vie?"La réponse: presque jamais .
Les affirmations, en tant que concept, sont merveilleuses. Le bon code a beaucoup de
if (...) throw ...
déclarations (et leurs proches commeObjects.requireNonNull
etMath.addExact
). Cependant, certaines décisions de conception ont considérablement limité l'utilité du mot -assert
clé - lui même.L'idée motrice derrière le
assert
mot-clé est l'optimisation prématurée, et la principale caractéristique est de pouvoir facilement désactiver toutes les vérifications. En fait, leassert
contrôles sont désactivés par défaut.Cependant, il est extrêmement important que les contrôles invariants continuent d'être effectués en production. En effet, une couverture de test parfaite est impossible et tout le code de production comportera des bogues que les assertions devraient aider à diagnostiquer et à atténuer.
Par conséquent, l'utilisation de
if (...) throw ...
devrait être préférée, tout comme elle est requise pour vérifier les valeurs des paramètres des méthodes publiques et pour lancerIllegalArgumentException
.Parfois, on pourrait être tenté d'écrire un chèque invariant qui prend un temps excessivement long à traiter (et qui est appelé assez souvent pour que cela ait de l'importance). Cependant, ces vérifications ralentiront les tests, ce qui est également indésirable. Ces vérifications chronophages sont généralement écrites sous forme de tests unitaires. Néanmoins, il peut parfois être judicieux d'utiliser
assert
pour cette raison.Ne l'utilisez pas
assert
simplement parce qu'il est plus propre et plus joli queif (...) throw ...
(et je le dis avec beaucoup de peine, car j'aime bien propre et joli). Si vous ne pouvez pas vous aider vous-même et pouvez contrôler le lancement de votre application, n'hésitez pas à l'utiliser,assert
mais activez toujours les assertions en production. Certes, c'est ce que j'ai tendance à faire. Je pousse pour une annotation lombok qui feraassert
agir plus commeif (...) throw ...
. Votez pour ça ici.(Rant: les développeurs JVM étaient un tas de codeurs horribles et optimisés prématurément. C'est pourquoi vous entendez parler de tant de problèmes de sécurité dans le plugin Java et la JVM. Ils ont refusé d'inclure des vérifications et des assertions de base dans le code de production, et nous continuons à payer le prix.)
la source
catch (Throwable t)
. Il n'y a aucune raison de ne pas essayer d'intercepter, de journaliser ou de réessayer / récupérer de OutOfMemoryError, AssertionError, etc.assert
mot-clé qui est mauvaise. Je vais modifier ma réponse pour qu'il soit plus clair que je fais référence au mot-clé, pas au concept.Voici le cas d'utilisation le plus courant. Supposons que vous allumiez une valeur énumérée:
Tant que vous gérez chaque cas, tout va bien. Mais un jour, quelqu'un ajoutera de la figue à votre énumération et oubliera de l'ajouter à votre instruction switch. Cela produit un bogue qui peut être difficile à détecter, car les effets ne se feront sentir qu'après avoir quitté l'instruction switch. Mais si vous écrivez votre commutateur comme ceci, vous pouvez l'attraper immédiatement:
la source
AssertionError
si les assertions sont activées (-ea
). Quel est le comportement souhaité en production? Un no-op silencieux et un désastre potentiel plus tard dans l'exécution? Probablement pas. Je proposerais une explicitethrow new AssertionError("Missing enum value: " + fruit);
.default
pour que le compilateur puisse vous avertir des cas manquants. Vous pouvezreturn
au lieu debreak
(cela peut nécessiter l'extraction de la méthode), puis gérer le cas manquant après le commutateur. De cette façon, vous obtenez à la fois l'avertissement et la possibilité de le faireassert
.Les assertions sont utilisées pour vérifier les conditions postérieures et les conditions préalables «ne devraient jamais échouer». Un code correct ne doit jamais échouer une assertion; lorsqu'ils se déclenchent, ils doivent indiquer un bug (si tout va bien à un endroit qui est proche de l'endroit où se trouve le problème).
Un exemple d'assertion pourrait être de vérifier qu'un groupe particulier de méthodes est appelé dans le bon ordre (par exemple, qui
hasNext()
est appelé avantnext()
dans unIterator
).la source
Regardons le bytecode compilé.
Nous conclurons que:
génère presque exactement le même bytecode que:
où
Assert.class.desiredAssertionStatus()
esttrue
quand-ea
est passé sur la ligne de commande, et false sinon.Nous utilisons
System.currentTimeMillis()
pour nous assurer qu'il ne sera pas optimisé (assert true;
did).Le champ synthétique est généré de sorte que Java n'a besoin d'appeler
Assert.class.desiredAssertionStatus()
qu'une seule fois au moment du chargement, puis il met en cache le résultat. Voir aussi: Quelle est la signification de "synthétique statique"?Nous pouvons vérifier cela avec:
Avec Oracle JDK 1.8.0_45, un champ statique synthétique a été généré (voir aussi: Quelle est la signification de "synthétique statique"? ):
avec un initialiseur statique:
et la méthode principale est:
Nous concluons que:
assert
: c'est un concept de langage Javaassert
pourrait être assez bien émulé avec des propriétés système-Pcom.me.assert=true
à remplacer-ea
sur la ligne de commande, et athrow new AssertionError()
.la source
catch (Throwable t)
clause peut également détecter les violations d'assertion? Pour moi, cela limite leur utilité uniquement au cas où le corps de l'assertion prend du temps, ce qui est rare.AssertionError
première et la relancer.Un exemple du monde réel, à partir d'une classe Stack (à partir de l' assertion dans les articles Java )
la source
Une assertion permet de détecter des défauts dans le code. Vous pouvez activer les assertions pour les tests et le débogage tout en les désactivant lorsque votre programme est en production.
Pourquoi affirmer quelque chose quand on sait que c'est vrai? Ce n'est vrai que lorsque tout fonctionne correctement. Si le programme a un défaut, ce n'est peut-être pas vrai. Détecter cela plus tôt dans le processus vous permet de savoir que quelque chose ne va pas.
Une
assert
instruction contient cette instruction avec unString
message facultatif .La syntaxe d'une instruction assert a deux formes:
Voici quelques règles de base qui régissent où les assertions doivent être utilisées et où elles ne doivent pas être utilisées. Les assertions doivent être utilisées pour:
Validation des paramètres d'entrée d'une méthode privée. PAS pour les méthodes publiques.
public
les méthodes doivent lever des exceptions régulières lorsqu'elles sont passées de mauvais paramètres.N'importe où dans le programme pour garantir la validité d'un fait qui est presque certainement vrai.
Par exemple, si vous êtes sûr qu'il ne s'agira que de 1 ou 2, vous pouvez utiliser une assertion comme celle-ci:
Les assertions ne doivent pas être utilisées pour:
Validation des paramètres d'entrée d'une méthode publique. Comme les assertions ne sont pas toujours exécutées, le mécanisme d'exception normal doit être utilisé.
Validation des contraintes sur quelque chose qui est entré par l'utilisateur. Comme ci-dessus.
Ne doit pas être utilisé pour des effets secondaires.
Par exemple, ce n'est pas une utilisation appropriée car ici l'assertion est utilisée pour son effet secondaire d'appeler la
doSomething()
méthode.Le seul cas où cela pourrait être justifié est lorsque vous essayez de savoir si les assertions sont activées ou non dans votre code:
la source
En plus de toutes les bonnes réponses fournies ici, le guide de programmation officiel de Java SE 7 contient un manuel assez concis sur l'utilisation
assert
; avec plusieurs exemples précis sur le moment où il est bon (et, surtout, mauvais) d'utiliser des assertions, et en quoi c'est différent de lever des exceptions.Lien
la source
Assert est très utile lors du développement. Vous l'utilisez quand quelque chose ne peut tout simplement pas se produire si votre code fonctionne correctement. Il est facile à utiliser et peut rester dans le code pour toujours, car il sera désactivé dans la vraie vie.
S'il y a une chance que la condition puisse se produire dans la vraie vie, vous devez la gérer.
Je l'adore, mais je ne sais pas comment l'activer dans Eclipse / Android / ADT. Il semble être désactivé même lors du débogage. (Il y a un fil à ce sujet, mais il fait référence au «Java vm», qui n'apparaît pas dans la configuration d'exécution ADT).
la source
Voici une assertion que j'ai écrite sur un serveur pour un projet Hibernate / SQL. Un bean entité avait deux propriétés effectivement booléennes, appelées isActive et isDefault. Chacun pouvait avoir une valeur "Y" ou "N" ou null, qui était traité comme "N". Nous voulons nous assurer que le client du navigateur est limité à ces trois valeurs. Donc, dans mes setters pour ces deux propriétés, j'ai ajouté cette affirmation:
Remarquez ce qui suit.
Cette assertion concerne uniquement la phase de développement. Si le client envoie une mauvaise valeur, nous l'attraperons tôt et le réparerons, bien avant d'atteindre la production. Les affirmations concernent les défauts que vous pouvez détecter tôt.
Cette affirmation est lente et inefficace. C'est bon. Les assertions peuvent être lentes. Nous ne nous en soucions pas car ce sont des outils de développement uniquement. Cela ne ralentira pas le code de production car les assertions seront désactivées. (Il y a un certain désaccord sur ce point, que j'aborderai plus tard.) Cela m'amène à mon prochain point.
Cette affirmation n'a aucun effet secondaire. J'aurais pu tester ma valeur par rapport à un ensemble final statique non modifiable, mais cet ensemble serait resté en production, où il ne serait jamais utilisé.
Cette assertion existe pour vérifier le bon fonctionnement du client. Ainsi, au moment où nous atteindrons la production, nous serons sûrs que le client fonctionne correctement, afin que nous puissions désactiver l'assertion en toute sécurité.
Certaines personnes demandent ceci: si l'assertion n'est pas nécessaire en production, pourquoi ne pas simplement les retirer lorsque vous avez terminé? Parce que vous en aurez toujours besoin lorsque vous commencerez à travailler sur la prochaine version.
Certaines personnes ont fait valoir que vous ne devriez jamais utiliser d'assertions, car vous ne pouvez jamais être sûr que tous les bogues ont disparu, vous devez donc les garder même en production. Et il est donc inutile d'utiliser l'instruction assert, car le seul avantage des assertions est que vous pouvez les désactiver. Par conséquent, selon cette réflexion, vous ne devriez (presque) jamais utiliser d'assertions. Je ne suis pas d'accord. Il est certainement vrai que si un test appartient à la production, vous ne devez pas utiliser d'assertion. Mais ce test ne pas à la production. Celui-ci sert à attraper un bogue qui n'atteindra probablement jamais la production, il peut donc être désactivé en toute sécurité lorsque vous avez terminé.
BTW, j'aurais pu l'écrire comme ceci:
C'est bien pour seulement trois valeurs, mais si le nombre de valeurs possibles augmente, la version HashSet devient plus pratique. J'ai choisi la version HashSet pour faire valoir mon point de vue sur l'efficacité.
la source
HashSet
apporte un avantage de vitesse sur unArrayList
. De plus, les créations d'ensemble et de liste dominent le temps de recherche. Ils iraient bien en utilisant une constante. Cela dit, +1.Les assertions sont essentiellement utilisées pour déboguer l'application ou elles sont utilisées en remplacement de la gestion des exceptions pour certaines applications afin de vérifier la validité d'une application.
L'assertion fonctionne au moment de l'exécution. Un exemple simple, qui peut expliquer tout le concept très simplement, est ici - Que fait le mot-clé assert en Java? (WikiAnswers).
la source
Les assertions sont désactivées par défaut. Pour les activer, nous devons exécuter le programme avec des
-ea
options (la granularité peut varier). Par exemplejava -ea AssertionsDemo
,.Il existe deux formats d'utilisation des assertions:
assert 1==2; // This will raise an AssertionError
.assert 1==2: "no way.. 1 is not equal to 2";
Cela soulèvera une AssertionError avec le message donné affiché aussi et c'est donc mieux. Bien que la syntaxe réelle soitassert expr1:expr2
où expr2 peut être n'importe quelle expression renvoyant une valeur, je l'ai utilisée plus souvent juste pour imprimer un message.la source
Pour récapituler (et cela est vrai de nombreux langages, pas seulement Java):
"assert" est principalement utilisé comme aide au débogage par les développeurs de logiciels pendant le processus de débogage. Les messages d'assertion ne doivent jamais apparaître. De nombreux langages offrent une option au moment de la compilation qui entraînera l'ignorance de toutes les «assertions», pour une utilisation lors de la génération de code de «production».
les "exceptions" sont un moyen pratique de gérer toutes sortes de conditions d'erreur, qu'elles représentent ou non des erreurs logiques, car, si vous rencontrez une condition d'erreur telle que vous ne pouvez pas continuer, vous pouvez simplement "les jeter en l'air", "où que vous soyez, en attendant que quelqu'un d'autre soit prêt à les" attraper ". Le contrôle est transféré en une seule étape, directement du code qui a levé l'exception, directement au gant du receveur. (Et le receveur peut voir la trace complète des appels qui ont eu lieu.)
De plus, les appelants de ce sous-programme n'ont pas à vérifier si le sous-programme a réussi: "si nous sommes ici maintenant, il doit avoir réussi, car sinon il aurait levé une exception et nous ne serions pas ici maintenant!" Cette stratégie simple rend la conception de code et le débogage beaucoup plus faciles.
Les exceptions permettent aux conditions d'erreur fatale d'être ce qu'elles sont: «des exceptions à la règle». Et, pour qu'ils soient gérés par un chemin de code qui est aussi "une exception à la règle ... " fly ball! "
la source
Les assertions sont des contrôles qui peuvent être désactivés. Ils sont rarement utilisés. Pourquoi?
result != null
car ces contrôles sont très rapides et il n'y a pratiquement rien à enregistrer.Alors, que reste-t-il? Des vérifications coûteuses des conditions devraient être vraies. Un bon exemple serait les invariants d'une structure de données comme RB-tree. En fait, dans
ConcurrentHashMap
JDK8, il y a quelques assertions significatives pour leTreeNodes
.Parfois, le chèque n'est pas vraiment cher, mais en même temps, vous êtes presque sûr qu'il passera. Dans mon code, il y a par exemple,
où je suis presque sûr que la liste que je viens de créer a des éléments uniques, mais je voulais documenter et revérifier.
la source
Fondamentalement, «affirmer vrai» passera et «affirmera faux» échouera. Voyons comment cela fonctionnera:
la source
assert
est un mot-clé. Il a été introduit dans JDK 1.4. Il existe deux types deassert
sassert
déclarationsassert
.Par défaut, toutes les
assert
instructions ne seront pas exécutées. Si uneassert
instruction reçoit false, elle déclenchera automatiquement une erreur d'assertion.la source