2192 votes

La comparaison de Java enum membres: == ou equals()?

Je sais que Java enums sont compilés pour les classes avec les constructeurs privés et un tas de public static membres. Lorsque l'on compare les deux membres d'une enum, j'ai toujours utilisé l' .equals(), par exemple

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

Cependant, je viens de venir un code qui utilise l'opérateur = == à la place:

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

J'ai été à la programmation en Java pour les+ de 5 ans, et j'ai cru comprendre la différence entre les deux, mais je suis encore à me gratter la tête à celui qui est plus correct. L'opérateur qui est celui que je dois utiliser?

2036voto

Reverend Gonzo Points 15504

Les deux sont techniquement correct. Si vous regardez le code source pour .equals(), tout simplement, il reporte à l' ==.

J'utilise ==, cependant, qui sera nulle coffre-fort.

1368voto

polygenelubricants Points 136838

Peut - == être utilisé sur enum?

Oui: les énumérations ont serré instance de contrôle qui vous permet d'utiliser == à comparer les instances. Voici la garantie fournie par la spécification du langage:

JLS 8.9 Enums

Un type enum n'a pas d'instances autres que celles définies par son enum constantes.

C'est une erreur de compilation pour tenter d'instancier explicitement un type enum. L' final clone méthode de Enum assure enum des constantes ne peut jamais être cloné, et le traitement spécial par le mécanisme de sérialisation s'assure que les instances dupliquées ne sont jamais créées à la suite de la désérialisation. Réfléchissant à l'instanciation des types enum est interdite. Ensemble, ces quatre choses s'assurer qu'aucune des instances d' enum type existent au-delà de celles définies par l' enum des constantes.

Car il n'existe qu'une seule instance de chaque enum constante, il est permis d'utiliser l' == de l'opérateur en place de l' equals méthode lorsque l'on compare les deux références de l'objet si il est connu qu'au moins l'un d'eux se réfère à un enum constante. ( equals Méthode de Enum est final méthode qui se borne à invoquer super.equals sur son argument et renvoie le résultat, réalisant ainsi une identité comparaison).

Cette garantie est suffisamment forte pour que Josh Bloch recommande, si vous insistez sur l'utilisation d'un singleton, la meilleure façon de la mettre en œuvre est l'utilisation d'un seul élément enum (voir: Efficace Java 2nd Edition, Point 3: Appliquer le singleton de la propriété avec un constructeur privé ou d'un type d'énumération; aussi la sécurité des Threads en Singleton)


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

Pour rappel, il doit être dit qu'en général, == n'est PAS une alternative viable à l' equals. Quand il est, cependant (comme avec enum), il y a deux différences importantes à prendre en compte:

== jamais jette NullPointerException

enum Color { BLACK, WHITE };

Color nothing = null;
if (nothing == Color.BLACK);      // runs fine
if (nothing.equals(Color.BLACK)); // throws NullPointerException

== est sous réserve de la compatibilité du type de vérifier au moment 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 - == être utilisés le cas échéant?

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

Article 1: Envisager statique usine méthodes à la place des constructeurs

[...] il permet immuable classe pour vous la garantie de l'absence de deux cas existent: a.equals(b) si et seulement si a==b. Si une classe rend cette garantie, puis à ses clients d'utiliser l' == opérateur au lieu de l' equals(Object) méthode, ce qui peut entraîner une amélioration des performances. Les types Enum fournir cette garantie.

Pour résumer, les arguments pour l'utilisation de == sur enum sont:

  • Elle fonctionne.
  • C'est plus rapide.
  • Il est plus sûr au moment de l'exécution.
  • Il est plus sûr au moment de la compilation.

124voto

Pascal Thivent Points 295221

À l'aide de == pour comparer deux valeurs enum fonctionne car il n'existe qu'un seul objet pour chaque constante enum.

Sur une note de côté, il n'y a effectivement pas besoin d'utiliser d' == écrire null code de sécurité si vous écrivez votre equals() comme ceci:

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

Il s'agit d'une pratique connue sous le nom de Comparer les Constantes De La Gauche que vous avez certainement devraient suivre.

73voto

Tobias Points 478

Comme d'autres l'ont dit, les deux == et .equals() de travail dans la plupart des cas. Le temps de compilation de certitude que vous n'êtes pas en comparant complètement différents types d'Objets que d'autres ont souligné est valide et bénéfique, cependant ce type de bug des objets de comparaison de deux différents moment de la compilation types serait également trouvé par FindBugs (et probablement par Eclipse/IntelliJ moment de la compilation des inspections), de sorte que le compilateur Java de trouver qu'il n'ajoute pas beaucoup plus de sécurité.

Cependant:

  1. Le fait qu' == jamais jette des NPE dans mon esprit, c'est un inconvénient de l' ==. Il ne devrait presque jamais une nécessité enum types null, depuis supplémentaires de l'état que vous souhaitez exprimer via null pouvez simplement être ajouté à l' enum comme une instance supplémentaire. Si c'est de façon inattendue null, je préfère avoir un NPE qu' == silencieusement de l'évaluation à la valeur false. Donc je suis en désaccord avec l' , c'est plus prudent au moment de l'exécution de l'opinion; il est préférable de prendre l'habitude de ne jamais laissez - enum valeurs @Nullable.
  2. L'argument que l' == est plus rapide est aussi faux. Dans la plupart des cas vous appellerai .equals() sur une variable dont le temps de compilation est de type enum classe, et dans ces cas, le compilateur ne peut pas savoir que c'est le même que == (en raison d'un enums' equals() méthode peut pas être modifiée) et permet d'optimiser l'appel de la fonction de distance. Je ne suis pas sûr si le compilateur ne le fait actuellement, mais si ça ne marche pas, et s'avère être un problème de performances en Java dans l'ensemble, alors, je préfère fixer le compilateur de 100 000 programmeurs Java changer leur style de programmation pour répondre à un particulier version compilateur caractéristiques de performance.
  3. enums sont des Objets. Pour tous les autres types d'Objet de la norme de comparaison est - .equals(), pas ==. Je pense qu'il est dangereux de faire une exception pour l' enums parce que vous pourriez accidentellement Objets de comparaison avec == au lieu de equals(), surtout si vous refactoriser un enum dans une situation de non-enum class. Dans le cas d'un refactoring, Il travaille point à partir de ci-dessus est faux. De savoir qu' == est correcte, vous devez savoir que la valeur en question est soit une enum ou un primitif; si c'était un non-enum classe, ce serait facile de manquer parce que le code serait encore de la compilation. Dans le cas d' .equals(), le seul cas dans lequel il est mauvais, c'est si les valeurs en question sont primitives; dans ce cas, le code ne sera même pas compiler et il est donc beaucoup plus difficile à manquer. Par conséquent, .equals() est beaucoup plus facile à identifier comme étant correcte, et est plus sûr contre les futures refactorings.

En fait, je pense que le langage Java doivent avoir défini == sur les Objets à l'appel .equals() sur la valeur de la main gauche, et d'introduire un opérateur séparées pour l'identité de l'objet, mais ce n'est pas la façon de Java, a été défini.

En résumé, je pense que les arguments sont en faveur de l'utilisation de .equals() pour enum types.

16voto

ChrisCantrell Points 828

Ici, c'est un brut de timing test 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());
    }   

}

Commentaire de l'IFs, un à un. Voici les deux se compare à partir de ci-dessus dans démonté byte-code:

 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

La première (est égal à) effectue un appel virtuel et tests le retour booléen à partir de la pile. La deuxième (==) compare l'objet d'adresses directement à partir de la pile. Dans le premier cas, il n'y a plus d'activité.

J'ai couru ce test plusieurs fois avec les deux IFs, un à la fois. Le "==" est un peu plus rapide.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X