Comparaison des membres de Java enum: = = ou equals ()?
je sais que les enums Java sont compilés pour des classes avec des constructeurs privés et un tas de membres statiques publics. Pour comparer deux membres d'un même enum, j'ai toujours utilisé .equals()
, par exemple
public useEnums(SomeEnum a)
{
if(a.equals(SomeEnum.SOME_ENUM_VALUE))
{
...
}
...
}
cependant, je viens de trouver un code qui utilise l'opérateur égal ==
au lieu de .égal ():
public useEnums2(SomeEnum a)
{
if(a == SomeEnum.SOME_ENUM_VALUE)
{
...
}
...
}
Quel est l'opérateur que je devrais utiliser?
14 réponses
les deux sont techniquement corrects. Si vous regardez le code source de .equals()
, il se reporte simplement à ==
.
j'utilise ==
, cependant, car cela ne sera pas sûr.
peut-on utiliser ==
sur enum
?
Oui: les enums 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 langue (souligné par moi):
JLS 8.9 Enums
un type enum n'a pas d'instances autres que celles définies par ses constantes enum.
C'est une erreur de compilation pour tenter d'instancier explicitement un type enum. La méthode
final clone
dansEnum
garantit que les constantesenum
ne peuvent jamais être clonées, et le traitement spécial par le mécanisme de sérialisation garantit que les instances dupliquées ne sont jamais créées à la suite de la desérialisation. L'instanciation réfléchissante des types enum est interdite. Ensemble, ces quatre éléments font en sorte qu'aucun cas de typeenum
n'existe au-delà de ceux définis par leenum
." constant.étant donné qu'il n'y a qu'une seule instance de chaque constante
enum
, , il est permis d'utiliser l'opérateur==
à la place de la méthodeequals
lorsqu'on compare deux références d'objet si l'on sait qu'au moins une d'entre elles fait référence à une constanteenum
1519510920". (La méthodeequals
dansEnum
est une méthodefinal
qui invoque simplementsuper.equals
sur son argument et renvoie le résultat, ainsi effectuer une comparaison d'identité.)
cette garantie est assez forte que Josh Bloch recommande, que si vous insistez sur l'utilisation du modèle singleton, la meilleure façon de le mettre en œuvre est d'utiliser un élément unique enum
(voir: Java efficace 2e édition, point 3: Faire respecter la propriété singleton avec un constructeur privé ou un type enum ; aussi sécurité du fil dans Singleton )
quelles sont les différences entre ==
et equals
?
pour rappel, il faut dire qu'en général, ==
n'est pas une alternative viable à equals
. Quand il est, cependant (comme avec enum
), il y a deux différences importantes à considérer:
==
ne jette jamais NullPointerException
enum Color { BLACK, WHITE };
Color nothing = null;
if (nothing == Color.BLACK); // runs fine
if (nothing.equals(Color.BLACK)); // throws NullPointerException
==
est soumis à la compatibilité de type vérifier à l'Heure de la compilation
enum Color { BLACK, WHITE };
enum Chiral { LEFT, RIGHT };
if (Color.BLACK.equals(Chiral.LEFT)); // compiles fine
if (Color.BLACK == Chiral.LEFT); // DOESN'T COMPILE!!! Incompatible types!
devrait-on utiliser ==
s'il y a lieu?
Bloch mentionne spécifiquement que les classes immuables qui ont un contrôle approprié sur leurs instances peuvent garantir à leurs clients que ==
est utilisable. enum
est spécifiquement mentionné à titre d'exemple.
Article 1: Envisager statique usine méthodes à la place de constructeurs
[...] elle permet à une classe immuable de garantir qu'il n'existe pas deux instances égales:
a.equals(b)
si et seulement sia==b
. Si une classe fait cette garantie, alors ses clients peuvent utiliser l'opérateur==
au lieu de la méthodeequals(Object)
, ce qui peut entraîner des performances améliorées. Les types Enum offrent cette garantie.
pour résumer, les arguments pour utiliser ==
sur enum
sont:
- ça marche.
- c'est plus rapide.
- c'est plus sûr à la course.
- c'est plus sûr à la compilation.
utilisant ==
pour comparer deux valeurs enum fonctionne parce qu'il n'y a qu'un objet pour chaque constante enum.
sur une note latérale, il n'est en fait pas nécessaire d'utiliser ==
pour écrire un code de sécurité nul si vous écrivez votre equals()
comme ceci:
public useEnums(SomeEnum a)
{
if(SomeEnum.SOME_ENUM_VALUE.equals(a))
{
...
}
...
}
il s'agit d'une pratique exemplaire connue sous le nom de comparez les constantes à partir de la gauche que vous devez absolument suivre.
comme d'autres l'ont dit, les deux ==
et .equals()
fonctionnent dans la plupart des cas. La certitude de temps de compilation que vous ne comparez pas des types complètement différents D'objets que d'autres ont fait remarquer est valide et bénéfique, Cependant le type particulier de bogue de comparer des objets de deux types de temps de compilation différents serait également trouvé par FindBugs (et probablement par Eclipse/IntelliJ compilent time inspections), de sorte que le compilateur Java trouver qu'il n'ajoute pas beaucoup de sécurité supplémentaire.
cependant:
- le fait que
==
ne jette jamais NPE dans mon esprit est un désavantage de==
. Il ne devrait presque jamais être nécessaire que les typesenum
soientnull
, car tout état supplémentaire que vous pourriez vouloir exprimer vianull
peut simplement être ajouté auenum
comme une instance supplémentaire. S'il est inattendunull
, je préfère avoir un NPE que==
évaluation silencieuse à fausse. Par conséquent, je ne suis pas d'accord avec l'opinion c'est plus sûr à l'Heure de roulage ; il vaut mieux prendre l'habitude de ne jamais laisserenum
valeurs être@Nullable
. - l'argument selon lequel
==
est plus rapide est également faux. Dans la plupart des cas, vous appellerez.equals()
sur 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==
(parce qu'une méthodeenum
'sequals()
ne peut pas être dépassée) et peut optimiser l'appel de la fonction. Je ne suis pas sûr que le compilateur le fasse actuellement, mais si ce n'est pas le cas, et s'il s'avère qu'il s'agit d'un problème de performance dans L'ensemble de Java, alors je préfère réparer le compilateur que d'avoir 100 000 programmeurs Java qui changent leur style de programmation pour s'adapter aux caractéristiques de performance d'une version particulière du compilateur. -
enums
sont des Objets. Pour tous les autres types d'Objet de l' la comparaison standard est.equals()
, pas==
. Je pense qu'il est dangereux de faire une exception pourenums
parce que vous pourriez finir par comparer accidentellement des objets avec==
au lieu deequals()
, surtout si vous reformulez unenum
dans une classe non-enum. Dans le cas d'un tel remaniement, le il fonctionne point d'en haut est erroné. Pour vous convaincre que l'utilisation de==
est correcte, vous devez vérifier si la valeur en question est soit une classeenum
, soit une classe primitive; si c'était une classe non -enum
, ce serait mal mais facile à manquer car le code serait encore compilé. Le seul cas où une utilisation de.equals()
serait erronée est si les valeurs en question étaient primitives; dans ce cas, le code ne compilerait pas donc il est beaucoup plus difficile de manquer. Par conséquent,.equals()
est beaucoup plus facile à identifier comme correct, et est plus sûr contre les futurs remaniements.
je pense en fait que la Java le langage devrait avoir défini = = sur les objets à appeler .equals () sur la valeur de gauche, et introduire un opérateur séparé pour l'identité de l'objet, mais ce N'est pas comme ça que Java a été défini.
En résumé, je pense que les arguments sont en faveur de l'utilisation de .equals()
pour enum
.
voici un essai de synchronisation brut pour comparer les deux:
import java.util.Date;
public class EnumCompareSpeedTest {
static enum TestEnum {ONE, TWO, THREE }
public static void main(String [] args) {
Date before = new Date();
int c = 0;
for(int y=0;y<5;++y) {
for(int x=0;x<Integer.MAX_VALUE;++x) {
if(TestEnum.ONE.equals(TestEnum.TWO)) {++c;}
if(TestEnum.ONE == TestEnum.TWO){++c;}
}
}
System.out.println(new Date().getTime() - before.getTime());
}
}
commente Les IFs un à la fois. Voici les deux comparaisons ci-dessus dans le code de byte démonté:
21 getstatic EnumCompareSpeedTest$TestEnum.ONE : EnumCompareSpeedTest.TestEnum [19]
24 getstatic EnumCompareSpeedTest$TestEnum.TWO : EnumCompareSpeedTest.TestEnum [25]
27 invokevirtual EnumCompareSpeedTest$TestEnum.equals(java.lang.Object) : boolean [28]
30 ifeq 36
36 getstatic EnumCompareSpeedTest$TestEnum.ONE : EnumCompareSpeedTest.TestEnum [19]
39 getstatic EnumCompareSpeedTest$TestEnum.TWO : EnumCompareSpeedTest.TestEnum [25]
42 if_acmpne 48
le premier (égal) effectue un appel virtuel et teste le booléen de retour de la pile. La seconde ( = = ) compare les adresses des objets directement à partir de la pile. Dans le premier cas, il n'y a plus d'activité.
j'ai fait ce test plusieurs fois avec les deux si un à la fois. Le "==" est un peu plus rapide.
je préfère utiliser ==
au lieu de equals
:
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 énums qui sont exactement les mêmes mais dans des pacakges séparés (ce n'est pas commun, mais cela pourrait arriver):
Première enum :
package first.pckg
public enum Category {
JAZZ,
ROCK,
POP,
POP_ROCK
}
Deuxième enum:
package second.pckg
public enum Category {
JAZZ,
ROCK,
POP,
POP_ROCK
}
alors supposons que vous utilisiez les égaux comme suivant dans item.category
qui est first.pckg.Category
mais vous importez le deuxième enum ( second.pckg.Category
) à la place du premier sans s'en rendre compte:
import second.pckg.Category;
...
Category.JAZZ.equals(item.getCategory())
donc vous obtiendrez tous les jours false
dû est un énum différent bien que vous attendez vrai parce que item.getCategory()
est JAZZ
. Et il pourrait être un peu difficile à voir.
donc, si vous utilisez l'opérateur ==
vous aurez une erreur de compilation:
opérateur == ne peut pas être appliqué à "second.pckg.Catégorie", " d'abord.pckg.La catégorie"
import second.pckg.Category;
...
Category.JAZZ == item.getCategory()
utiliser autre chose que ==
pour comparer les constantes d'enum est absurde. C'est comme comparer class
avec equals
– ne le faites pas!
cependant, il y avait un méchant bug (BugId 6277781 ) dans Sun JDK 6u10 et plus tôt qui pourrait être intéressant pour des raisons historiques. Ce bogue a empêché l'utilisation correcte de ==
sur les énums désérialisés, bien que ce soit sans doute un cas de coin.
Enums sont des classes qui renvoient une instance (comme singletons) pour chaque constante d'énumération déclarée par public static final field
(immuable) de sorte que ==
opérateur pourrait être utilisé pour vérifier leur égalité plutôt que d'utiliser equals()
méthode
En bref, les deux ont des avantages et des inconvénients.
d'une part, il a des avantages à utiliser ==
, comme décrit dans les autres réponses.
d'autre part, si vous remplacez pour une raison quelconque les enum par une approche différente (cas de classe normale), après avoir utilisé ==
vous mord. (BTDT.)
la raison pour laquelle enums fonctionne facilement avec == est que chaque instance définie est aussi un singleton. Donc la comparaison d'identité avec == fonctionnera toujours.
mais utiliser = = parce qu'il fonctionne avec enums signifie que tout votre code est étroitement couplé avec l'utilisation de cet enum.
par exemple: Enums peut implémenter une interface. Supposons que vous utilisez actuellement un enum qui implémente Interface1. Si plus tard, quelqu'un change ou introduit une nouvelle classe Impl1 comme une implémentation de la même interface. Ensuite, si vous commencez à utiliser les instances D'Impl1, vous aurez beaucoup de code à changer et à tester en raison de l'utilisation antérieure de ==.
par conséquent, il est préférable de suivre ce qui est considéré comme une bonne pratique à moins qu'il n'y ait un gain justifiable.
je veux compléter polygenelubricants réponse:
je préfère personnellement les égaux(). Mais c'lac le type de contrôle de compatibilité. Je pense que c'est une limitation importante.
pour faire vérifier la compatibilité du type au moment de la compilation, déclarez et utilisez une fonction personnalisée dans votre enum.
public boolean isEquals(enumVariable) // compare constant from left
public static boolean areEqual(enumVariable, enumVariable2) // compare two variable
avec ceci, vous avez obtenu tous les avantages des deux solutions: la protection NPE, facile à lire le code et le contrôle de compatibilité de type à le temps de compilation.
je recommande également d'ajouter une valeur non définie pour enum.
Enum au milieu est un ensemble d'entiers constants. "=="est tout aussi valide et correct que si vous compariez deux entiers.
je voudrais souligner explicitement cette différence spécifique entre l'opérateur ==
et la méthode equals()
:"
la méthode equals()
vise à vérifier si le contenu de l'objet ou des objets auxquels renvoie la ou les variables de référence en cause sont les mêmes.
l'opérateur ==
vérifie si la(Les) variable(s) de référence en cause renvoie (NT) au même objet .
c'est à la classe de mise en œuvre de fournir cette différenciation selon les besoins de l'application.
sinon le comportement par défaut sera tel que fourni par la classe Object
(en Java) où comme expliqué dans http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Object.html#equals (java.lang.Objet) :
la méthode
equals
pour la classeObject
met en œuvre les relation d'équivalence la plus discriminante possible sur les objets; c'est-à-dire pour toute valeur de référence non nullex
ety
, cette méthode renvoietrue
si et seulement six
ety
se réfèrent au même objet (x == y
a la valeurtrue
).