Je sais que les énumérations Java sont compilées en classes avec des constructeurs privés et un groupe de membres statiques publics. Lorsque je compare deux membres d'une énumération donnée, j'ai toujours utilisé .equals()
, par exemple
public useEnums(SomeEnum a)
{
if(a.equals(SomeEnum.SOME_ENUM_VALUE))
{
...
}
...
}
Cependant, je suis juste tombé sur un code qui utilise l'opérateur égal ==
au lieu de .equals ():
public useEnums2(SomeEnum a)
{
if(a == SomeEnum.SOME_ENUM_VALUE)
{
...
}
...
}
Quel opérateur dois-je utiliser?
Réponses:
Les deux sont techniquement corrects. Si vous regardez le code source
.equals()
, il s'en remet simplement à==
.J'utilise
==
, cependant, car ce sera sans danger.la source
.equals()
intégrer? Je sais que non.Peut
==
être utilisé surenum
?Oui: les énumérations ont des contrôles d'instance serrés qui vous permettent d'utiliser
==
pour comparer des instances. Voici la garantie fournie par la spécification de la langue (je souligne):Cette garantie est suffisamment forte pour que Josh Bloch recommande que si vous insistez pour utiliser le modèle singleton, la meilleure façon de l'implémenter est d'utiliser un seul élément
enum
(voir: Effective Java 2nd Edition, Item 3: Enforce the singleton property with a constructeur privé ou type enum ; également Thread safety in Singleton )Quelles sont les différences entre
==
etequals
?Pour rappel, il faut dire qu'en général, ce
==
n'est PAS une alternative viable àequals
. Quand c'est le cas (comme avecenum
), il y a deux différences importantes à considérer:==
ne jette jamaisNullPointerException
==
est soumis à une vérification de compatibilité des types lors de la compilationDoit
==
être utilisé le cas échéant?Bloch mentionne spécifiquement que les classes immuables qui ont un contrôle approprié sur leurs instances peuvent garantir à leurs clients qu'elles
==
sont utilisables.enum
est spécifiquement mentionné pour illustrer.Pour résumer, les arguments pour utiliser
==
onenum
sont:la source
Color nothing = null;
est IMHO un bug et devrait être corrigé, votre énumération a deux valeurs, pas trois ( voir le commentaire de Tom Hawtin) 4. Il est plus sûr au moment de la compilation : OK, maisequals
reviendrait quand mêmefalse
. Au final, je ne l'achète pas, je préfèreequals()
pour la lisibilité (voir le commentaire de Kevin).foo.equals(bar)
c'est plus lisible quefoo == bar
Utiliser
==
pour comparer deux valeurs d'énumération fonctionne, car il n'y a qu'un seul objet pour chaque constante d'énumération.Sur une note latérale, il n'est en fait pas nécessaire d'utiliser
==
pour écrire du code null-safe, si vous écrivez votreequals()
comme ceci:Il s'agit d'une meilleure pratique connue sous le nom de comparaison des constantes de gauche que vous devez absolument suivre.
la source
.equals()
ingénierie des valeurs de chaîne, mais je pense toujours que c'est une façon merdique d'écrire du code null-safe. Je préférerais de loin avoir un opérateur (ou une méthode, mais je sais que [objet nul] .equals ne sera jamais sans valeur nulle en Java en raison du fonctionnement de l'opérateur point) qui est toujours sans valeur nulle, quel que soit le l'ordre dans lequel il est utilisé. Sémantiquement, l'opérateur «égal» doit toujours commuter.?.
), je continuerai à utiliser cette pratique lors de la comparaison avec les constantes et, TBH, je ne le trouve pas merdique, peut-être juste moins "naturel".null
énumération est généralement une erreur. Vous avez cette énumération de toutes les valeurs possibles, et en voici une autre!@Nullable
, je considère que Comparer les constantes de gauche est un contre-motif car il répand l'ambiguïté sur les valeurs qui peuvent ou non être nulles. Les types énum ne devraient presque jamais l'être@Nullable
, donc une valeur nulle serait une erreur de programmation; dans un tel cas, plus vous lancez NPE tôt, plus vous risquez de trouver votre erreur de programmation là où vous l'avez autorisée à être nulle. Donc, "la meilleure pratique ... que vous devez absolument suivre" est tout à fait erronée en ce qui concerne les types d'énumération.Comme d' autres l' ont dit, à la fois
==
et le.equals()
travail dans la plupart des cas. La certitude de temps de compilation que vous ne comparez pas des types d'objets complètement différents que d'autres ont signalés est valide et bénéfique, mais le type particulier de bogue de comparaison d'objets de deux types de temps de compilation différents serait également trouvé par FindBugs (et probablement par Inspections de temps de compilation Eclipse / IntelliJ), donc le compilateur Java qui le trouve n'ajoute pas beaucoup de sécurité supplémentaire.Toutefois:
==
jette jamais NPE dans mon esprit est un inconvénient de==
. Il ne devrait presque jamais y avoir besoin deenum
typesnull
, car tout état supplémentaire que vous souhaitez exprimer vianull
peut simplement être ajouté à l'enum
instance supplémentaire. Si cela se produit de manière inattenduenull
, je préfère avoir un NPE que d'==
évaluer silencieusement à faux. Par conséquent, je ne suis pas d'accord avec l' opinion qu'il est plus sûr au moment de l'exécution ; il vaut mieux prendre l'habitude de ne jamais laisser deenum
valeurs@Nullable
.==
est plus rapide est également faux. Dans la plupart des cas, vous appellerez.equals()
une variable dont le type de temps de compilation est la classe enum, et dans ces cas, le compilateur peut savoir que c'est la même chose que==
(carenum
laequals()
méthode d'un ne peut pas être remplacée) et peut optimiser l'appel de fonction un moyen. Je ne sais pas si le compilateur fait actuellement cela, mais si ce n'est pas le cas, et s'avère être un problème de performance dans Java dans l'ensemble, je préfère corriger le compilateur plutôt que 100 000 programmeurs Java modifient leur style de programmation en fonction de les caractéristiques de performance d'une version de compilateur particulière.enums
sont des objets. Pour tous les autres types d'objets, la comparaison standard ne l'est.equals()
pas==
. Je pense qu'il est dangereux de faire une exceptionenums
car vous pourriez finir par comparer accidentellement des objets avec==
au lieu deequals()
, surtout si vous refactorisez unenum
en une classe non énumérée. Dans le cas d'une telle refactorisation, le point Ça marche d'en haut est faux. Pour vous convaincre qu'une utilisation de==
est correcte, vous devez vérifier si la valeur en question est uneenum
ou une primitive; s'il s'agissait d'une non-enum
classe, ce serait faux mais facile à manquer car le code serait toujours compilé. Le seul cas où une utilisation de.equals()
serait erroné si les valeurs en question étaient primitives; dans ce cas, le code ne serait pas compilé, il est donc beaucoup plus difficile à manquer. Par conséquent, il.equals()
est beaucoup plus facile de l'identifier comme étant correct et il est plus sûr contre les remaniements futurs.En fait, je pense que le langage Java aurait dû définir == sur les objets pour appeler .equals () sur la valeur de gauche, et introduire un opérateur distinct pour l'identité de l'objet, mais ce n'est pas ainsi que Java a été défini.
En résumé, je pense toujours que les arguments sont en faveur de l'utilisation
.equals()
pour lesenum
types.la source
enum
commeswitch
cible, donc ils sont un peu spéciaux.String
s sont un peu spéciaux aussi.Je préfère utiliser
==
plutôt queequals
:Une autre raison, en plus des autres déjà discutées ici, est que vous pourriez introduire un bogue sans vous en rendre compte. Supposons que vous ayez ces énumérations qui sont exactement les mêmes mais dans des pacakges séparés (ce n'est pas courant, mais cela pourrait arriver):
Première énumération :
Deuxième énumération:
Supposez ensuite que vous utilisez les égaux comme suivant dans
item.category
lequel se trouvefirst.pckg.Category
mais que vous importez le deuxième enum (second.pckg.Category
) à la place du premier sans vous en rendre compte:Donc , vous obtiendrez AllWays à
false
cause est un autre ENUM bien que vous attendez vrai parce queitem.getCategory()
estJAZZ
. Et cela pourrait être un peu difficile à voir.Donc, si vous utilisez plutôt l'opérateur,
==
vous aurez une erreur de compilation:la source
Voici un test de synchronisation brut pour comparer les deux:
Commentez les FI une par une. Voici les deux comparaisons ci-dessus en octet-code démonté:
Le premier (égal) effectue un appel virtuel et teste le retour booléen de la pile. Le second (==) compare les adresses des objets directement à partir de la pile. Dans le premier cas, il y a plus d'activité.
J'ai effectué ce test plusieurs fois avec les deux FI, un à la fois. Le "==" est toujours un peu plus rapide.
la source
En cas d'énumération, les deux sont corrects et corrects !!
la source
tl; dr
Une autre option est la
Objects.equals
méthode utilitaire.Objects.equals
pour une sécurité nulleUne troisième option est la
equals
méthode statique trouvée sur laObjects
classe d'utilitaires ajoutée à Java 7 et versions ultérieures.Exemple
Voici un exemple utilisant l'
Month
énumération.Avantages
Je trouve quelques avantages à cette méthode:
true
false
NullPointerException
Comment ça fonctionne
Quelle est la logique utilisée par
Objects.equals
?Voyez par vous-même, à partir du code source Java 10 d' OpenJDK :
la source
Utiliser autre chose que
==
de comparer des constantes enum est un non-sens. C'est comme comparer desclass
objets avecequals
- ne le faites pas!Cependant, il y avait un bogue désagréable (BugId 6277781 ) dans Sun JDK 6u10 et versions antérieures qui pouvait être intéressant pour des raisons historiques. Ce bogue a empêché une utilisation correcte de
==
sur les énumérations désérialisées, bien qu'il s'agisse sans doute d'un cas d'angle.la source
Les énumérations sont des classes qui renvoient une instance (comme des singletons) pour chaque constante d'énumération déclarée par
public static final field
(immuable) afin que l'==
opérateur puisse être utilisé pour vérifier leur égalité plutôt que d'utiliser laequals()
méthodela source
La raison pour laquelle les énumérations fonctionnent facilement avec == est que chaque instance définie est également un singleton. La comparaison d'identité à l'aide de == fonctionnera donc toujours.
Mais utiliser == parce qu'il fonctionne avec des énumérations signifie que tout votre code est étroitement associé à l'utilisation de cette énumération.
Par exemple: les énumérations peuvent implémenter une interface. Supposons que vous utilisez actuellement une énumération qui implémente Interface1. Si plus tard, quelqu'un la modifie ou introduit une nouvelle classe Impl1 en tant qu'implémentation de la même interface. Ensuite, si vous commencez à utiliser des instances d'Impl1, vous aurez beaucoup de code à modifier et à tester en raison de l'utilisation précédente de ==.
Par conséquent, il est préférable de suivre ce qui est considéré comme une bonne pratique, sauf s'il y a un gain justifiable.
la source
L'une des règles du sondeur est
Enum values should be compared with "=="
. Les raisons sont les suivantes:Enfin,
==
on enums est sans doute plus lisible (moins verbeux) queequals()
.la source
Bref, les deux ont des avantages et des inconvénients.
D'une part, il présente des avantages à utiliser
==
, comme décrit dans les autres réponses.D'un autre côté, si pour une raison quelconque, vous remplacez les énumérations par une approche différente (instances de classe normales), après avoir utilisé des
==
morsures. (BTDT.)la source
Je veux compléter la réponse des polygénelubrifiants:
Personnellement, je préfère equals (). Mais c'est la vérification de compatibilité des types. Je pense que c'est une limitation importante.
Pour faire vérifier la compatibilité des types au moment de la compilation, déclarez et utilisez une fonction personnalisée dans votre énumération.
Avec cela, vous avez tous les avantages des deux solutions: protection NPE, code facile à lire et vérification de la compatibilité des types au moment de la compilation.
Je recommande également d'ajouter une valeur UNDEFINED pour enum.
la source
==
? Avec==
vous bénéficiez d'une protection NPE, d'un code facile à lire et d'une vérification de la compatibilité des types de temps, et vous obtenez tout cela sans écrire de méthodes personnalisées de type égal.UNDEFINED
valeur est probablement une bonne idée. Bien sûr, dans Java 8, vous utiliseriezOptional
plutôt un .