Comparaison des membres enum Java: == ou égal ()?

Je sais que les énumérations Java sont compilées en classes avec des constructeurs privés et un groupe de membres statiques publics. En comparant deux membres d’un enum donné, j’ai toujours utilisé .equals() , par exemple

 public useEnums(SomeEnum a) { if(a.equals(SomeEnum.SOME_ENUM_VALUE)) { ... } ... } 

Cependant, je viens de trouver du code qui utilise l’opérateur égal à == au lieu de .equals ():

 public useEnums2(SomeEnum a) { if(a == SomeEnum.SOME_ENUM_VALUE) { ... } ... } 

Quel opérateur est celui que je devrais utiliser?

Les deux sont techniquement corrects. Si vous regardez le code source pour .equals() , il se contente simplement de == .

J’utilise cependant == , car ce sera sans danger.

Peut == être utilisé sur enum ?

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 (accent mis par moi):

JLS 8,9 Enums

Un type enum n’a aucune instance autre 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 de final clone dans Enum garantit que les constantes enum ne peuvent jamais être clonées, et le traitement spécial par le mécanisme de sérialisation garantit que les instances en double ne sont jamais créées suite à la désérialisation. L’instanciation réfléchie des types enum est interdite. Ensemble, ces quatre éléments garantissent qu’aucune instance de type enum n’existe au-delà de celles définies par les constantes enum .

Comme 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éthode equals lors de la comparaison de deux références d’object si l’on sait qu’au moins l’une d’entre elles fait référence à une constante enum . (La méthode equals dans Enum est une méthode final qui invoque simplement super.equals sur son argument et renvoie le résultat, effectuant ainsi une comparaison d’identité.)

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 consiste à utiliser une enum à un seul élément (voir: Effective Java 2nd Edition, élément 3: appliquer la propriété singleton avec un constructeur privé ou un type enum ; aussi la sécurité des threads dans Singleton )


Quelles sont les différences entre == et equals ?

Pour rappel, il faut dire que généralement, == n’est PAS une alternative viable aux equals . Quand c’est le cas (comme avec enum ), il y a deux différences importantes à considérer:

== ne lève jamais NullPointerException

 enum Color { BLACK, WHITE }; Color nothing = null; if (nothing == Color.BLACK); // runs fine if (nothing.equals(Color.BLACK)); // throws NullPointerException 

== est soumis à une vérification de compatibilité de type au moment de la compilation

 enum Color { BLACK, WHITE }; enum Chiral { LEFT, RIGHT }; if (Color.BLACK.equals(Chiral.LEFT)); // comstacks fine if (Color.BLACK == Chiral.LEFT); // DOESN'T COMPILE!!! Incompatible types! 

Devrait == être utilisé quand applicable?

Bloch mentionne spécifiquement que les classes immuables qui contrôlent correctement leurs instances peuvent garantir à leurs clients que == est utilisable. enum est spécifiquement mentionné pour illustrer.

Élément 1: Envisagez des méthodes de fabrique statiques au lieu de constructeurs

[…] cela permet à une classe immuable de garantir qu’il n’existe pas deux instances égales: a.equals(b) si et seulement si a==b . Si une classe fait cette garantie, ses clients peuvent utiliser l’opérateur == au lieu de la méthode equals(Object) , ce qui peut améliorer les performances. Les types Enum fournissent cette garantie.

Pour résumer, les arguments pour utiliser == sur enum sont les suivants:

  • Ça marche.
  • C’est plus rapide.
  • C’est plus sûr à l’exécution.
  • C’est plus sûr au moment de la compilation.

Utiliser == pour comparer deux valeurs d’énumération fonctionne car il n’y a qu’un seul object pour chaque constante d’énumération.

En passant, il n’y a pas besoin d’utiliser == pour écrire un code sécurisé nul si vous écrivez vos equals() comme ceci:

 public useEnums(SomeEnum a) { if(SomeEnum.SOME_ENUM_VALUE.equals(a)) { ... } ... } 

Ceci est une meilleure pratique connue sous le nom de Compare Constants From The Left que vous devez absolument suivre.

Comme d’autres l’ont dit, les deux == et .equals() fonctionnent dans la plupart des cas. La certitude de compilation que vous ne comparez pas complètement différents types d’objects que d’autres ont mis en évidence est valable et bénéfique, mais FindBugs (et probablement par Eclipse / IntelliJ comstacknt les inspections de temps), de sorte que le compilateur Java le trouve sans append une sécurité supplémentaire.

Toutefois:

  1. Le fait que == ne jette jamais NPE dans mon esprit est un inconvénient de == . Les types enum ne devraient jamais être null , car tout état supplémentaire que vous souhaitez exprimer via null peut simplement être ajouté à l’ enum tant enum supplémentaire. S’il est inopinément null , je préfère avoir un NPE que == en évaluant silencieusement à false. Par conséquent, je ne suis pas d’accord avec le fait qu’il est plus sûr à l’avis d’exécution ; il vaut mieux prendre l’habitude de ne jamais laisser les valeurs d’ enum @Nullable .
  2. L’argument selon lequel == est plus rapide est également faux. Dans la plupart des cas, vous appelez .equals() sur une variable dont le type de compilation est la classe enum et, dans ces cas, le compilateur peut savoir que c’est la même chose que == (car la méthode equals() un enum peut ne pas être annulé) 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 que cela se révèle être un problème de performance dans Java, je préfère réparer le compilateur que 100 000 programmeurs Java modifient leur style de programmation en conséquence. caractéristiques de performance d’une version particulière du compilateur.
  3. enums sont des objects. Pour tous les autres types d’objects, la comparaison standard est .equals() , pas == . Je pense qu’il est dangereux de faire une exception pour les enums car vous pourriez finir par comparer accidentellement des objects avec == au lieu des equals() , en particulier si vous refactorez un enum dans une classe non-enum. Dans le cas d’un tel refactoring, le point It works from above est erroné. Pour vous convaincre qu’une utilisation de == est correcte, vous devez vérifier si la valeur en question est une enum ou une primitive. si c’était une classe non- enum , ce serait faux mais facile à rater car le code serait toujours compilé. Le seul cas où une utilisation de .equals() serait erronée est que les valeurs en question soient des primitives; dans ce cas, le code ne comstackrait pas, il est donc beaucoup plus difficile de le rater. Par conséquent, .equals() est beaucoup plus facile à identifier comme correct et est plus sûr contre les refactorings futurs.

Je pense en fait que le langage Java aurait dû définir == sur les objects pour appeler .equals () à gauche et introduire un opérateur distinct pour l’identité de l’object, 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 de .equals() pour les types enum .

Voici un test de temps brut pour comparer les deux:

 import java.util.Date; public class EnumCompareSpeedTest { static enum TestEnum {ONE, TWO, THREE } public static void main(Ssortingng [] args) { Date before = new Date(); int c = 0; for(int y=0;y<5;++y) { for(int x=0;x 

Commentez les FI une à la fois. Voici les deux comparaisons ci-dessus en byte-code désassemblé:

  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 à partir de la stack. Le second (==) compare les adresses des objects directement depuis la stack. Dans le premier cas, il y a plus d'activité.

J'ai effectué ce test plusieurs fois avec les deux IF, l'une après l'autre. Le "==" est toujours un peu plus rapide.

En cas de énumération les deux sont corrects et corrects !!

Je préfère utiliser == au lieu d’ equals :

Une autre raison, en plus des autres points déjà discutés ici, est que vous pourriez introduire un bogue sans vous en rendre compte. Supposons que vous ayez cette énumération qui est exactement la même mais dans des combinaisons séparées (ce n’est pas courant, mais cela pourrait arriver):

Premier 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 } 

Supposons ensuite que vous item.category les égaux comme next dans item.category qui est first.pckg.Category mais que vous importez le second enum ( second.pckg.Category ) à la place du premier sans le réaliser:

 import second.pckg.Category; ... Category.JAZZ.equals(item.getCategory()) 

Donc, vous obtiendrez toujours une false due est une énumération différente bien que vous vous attendiez à vrai car item.getCategory() est JAZZ . Et ce pourrait être un peu difficile à voir.

Donc, si vous utilisez plutôt l’opérateur == vous aurez une erreur de compilation:

operator == ne peut être appliqué à “second.pckg.Category”, “first.pckg.Category”

 import second.pckg.Category; ... Category.JAZZ == item.getCategory() 

Utiliser autre chose que == pour comparer les constantes d’énumération est un non-sens. C’est comme comparer class objects de class avec des equals – ne le faites pas!

Cependant, Sun JDK 6u10 et les versions antérieures comportaient un bug important (bug n ° 6277781 ) qui pourrait être intéressant pour des raisons historiques. Ce bogue empêchait l’utilisation correcte de == sur les énumérations désérialisées, bien que ce soit sans doute un cas particulier.

Les énumérations 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 l’opérateur == puisse être utilisé pour vérifier leur égalité plutôt que la méthode equals()

En 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 vous remplacez les énumérations avec une approche différente (instances de classe normales), avoir utilisé == vous mord. (BTDT.)

Les énumérations de raison fonctionnent facilement avec == parce que chaque instance définie est également un singleton. Donc, la comparaison d’identité utilisant == fonctionnera toujours.

Mais utiliser == parce que cela fonctionne avec des énumérations signifie que tout votre code est étroitement lié à l’utilisation de cette énumération.

Par exemple: Enums peut implémenter une interface. Supposons que vous utilisez actuellement une énumération qui implémente Interface1. Si plus tard, quelqu’un le modifie ou introduit une nouvelle classe Impl1 comme 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 antérieure de ==.

Par conséquent, il est préférable de suivre ce qui est considéré comme une bonne pratique, sauf en cas de gain justifiable.

Je veux compléter les polygenélubrifiants répondre:

Personnellement, je préfère les égaux (). Mais c’est la vérification de compatibilité de type. Ce que je pense est une limitation importante.

Pour vérifier la compatibilité des types lors 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 cela, vous bénéficiez de tous les avantages des deux solutions: protection NPE, code de lecture facile et vérification de la compatibilité des types au moment de la compilation.

Je recommande également d’append une valeur UNDEFINED pour enum.

Vous pouvez utiliser: ==, equals () ou switch () pour comparer Enums, tous sont techniquement vrais et répondront à vos besoins.

Consultez ce tutoriel pour en savoir plus sur les opérations courantes de Enum: Comment utiliser Enums dans Java

Enum au milieu est un ensemble de nombres entiers constants. “==” est tout aussi valide que si vous compariez deux nombres entiers.

Je voudrais explicitement mettre en évidence cette différence spécifique entre la méthode == et la méthode equals() :

La méthode equals() est destinée à vérifier si le contenu du ou des objects auxquels la ou les variables de référence impliquées font référence est le même.

L’opérateur == vérifie si la ou les variables de référence impliquées font référence au même object .

Il appartient à la classe d’implémentation de fournir cette différenciation en fonction des besoins de l’application.

Sinon, le comportement par défaut sera celui fourni par la classe Object (en Java), comme expliqué dans http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Object.html#equals ( java.lang.Object) :

La méthode equals pour la classe Object implémente la relation d’équivalence la plus discriminante possible sur les objects; c’est-à-dire que pour toute valeur de référence non nulle x et y , cette méthode renvoie true si et seulement si x et y rapportent au même object ( x == y a la valeur true ).