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?

1452
demandé sur GURMEET SINGH 2009-11-17 20:26:27

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.

1310
répondu Reverend Gonzo 2011-10-10 15:55:55

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 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 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 type enum n'existe au-delà de ceux définis par le enum ." 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éthode equals 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 constante enum 1519510920". (La méthode equals dans Enum est une méthode final qui invoque simplement super.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 si a==b . Si une classe fait cette garantie, alors ses clients peuvent utiliser l'opérateur == au lieu de la méthode equals(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.
980
répondu polygenelubricants 2017-12-07 09:06:45

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.

72
répondu Pascal Thivent 2009-11-17 17:53:22

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:

  1. 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 types enum soient null , car tout état supplémentaire que vous pourriez vouloir exprimer via null peut simplement être ajouté au enum comme une instance supplémentaire. S'il est inattendu null , 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 laisser enum valeurs être @Nullable .
  2. 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éthode enum 's equals() 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.
  3. 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 pour enums parce que vous pourriez finir par comparer accidentellement des objets avec == au lieu de equals() , surtout si vous reformulez un enum 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 classe enum , 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 .

56
répondu Tobias 2015-06-04 03:43:54

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.

12
répondu ChrisCantrell 2011-10-14 21:19:26

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() 
11
répondu Pau 2017-04-21 07:31:45

dans le cas d'enum les deux sont corrects et justes!!

10
répondu Suraj Chandran 2011-11-23 13:03:10

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.

4
répondu Tomas 2015-10-26 20:40:01

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

4
répondu ΦXocę 웃 Пepeúpa ツ 2015-11-07 15:21:13

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.)

1
répondu glglgl 2017-06-05 20:05:39

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.

1
répondu Dev Amitabh 2017-12-12 03:19:17

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.

0
répondu Christ 2014-10-17 08:43:54

Enum au milieu est un ensemble d'entiers constants. "=="est tout aussi valide et correct que si vous compariez deux entiers.

-3
répondu Kamil Tomasz Jarmusik 2018-02-15 21:24:42

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 classe Object 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 nulle x et y , cette méthode renvoie true si et seulement si x et y se réfèrent au même objet ( x == y a la valeur true ).

-4
répondu sangv 2015-10-19 22:51:21