1723 votos

¿Comparando los miembros enum Java: == o equals()?

Sé que Java las enumeraciones son compilados a clases con los constructores privados y un montón de público a los miembros estáticos. Cuando se comparan dos de los miembros de una enumeración, siempre he utilizado .equals(), por ejemplo.

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

Sin embargo, acabo de venir a través de un código que utiliza el operador es igual a == lugar:

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

He sido programación en Java por lo menos 5 años, y yo pensaba que entendía la diferencia entre los dos -, pero todavía estoy rascándome la cabeza en la que uno es más correcto. Que operador es el que debe utilizar?

1560voto

Reverend Gonzo Puntos 15504

Ambas son técnicamente correctas. Si miras el código fuente de .equals() , simplemente aplaza a == .

Utilizo == , sin embargo, ya que será nulo seguro.

1106voto

polygenelubricants Puntos 136838

Puede == utilizarse en enum?

Sí: las enumeraciones han apretado instancia de controles que permite utilizar == para comparar instancias. Aquí está la garantía que proporciona el lenguaje de especificación:

JLS 8.9 Enumeraciones

Un tipo de enumeración no tiene instancias diferentes a los definidos por sus constantes de enumeración.

Se trata de un error en tiempo de compilación para intentar explícitamente crear una instancia de un tipo enum. La final clone método en Enum asegura que enum constantes nunca puede ser clonado, y el trato especial por el mecanismo de serialización asegura que duplicar los casos nunca se crean como resultado de la deserialización. Reflexivo de la creación de instancias de tipos de enumeración está prohibido. En conjunto, estos cuatro cosas asegurarse de que no hay instancias de un enum tipo de existir más allá de las definidas por el enum constantes.

Porque no es sólo una instancia de cada uno de los enum constante, está permitido el uso de la == operador en lugar de la equals método para comparar dos referencias a objetos, si se conoce que al menos uno de ellos se refiere a un enum constante. (La equals método en Enum es final método que simplemente invoca super.equals sobre su argumento y devuelve el resultado, realizando así una identidad de comparación.)

Esta garantía es suficientemente fuerte como para que Josh Bloch recomienda, que si insisten en usar el patrón singleton, la mejor manera de implementarlo es el uso de un único elemento enum (ver: Efectivo Java 2ª Edición, Punto 3: Aplicar el singleton de la propiedad con un constructor privado o de un tipo enum; también la seguridad de los subprocesos en Singleton)


¿Cuáles son las diferencias entre == y equals?

Como recordatorio, hay que decir que, en general, == NO es una alternativa viable para equals. Cuando es así, sin embargo (como enum), hay dos diferencias importantes a considerar:

== nunca lanza NullPointerException

enum Color { BLACK, WHITE };

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

== está sujeto a tipo de comprobación de compatibilidad en tiempo de compilación

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!

Debe == utilizarse cuando sea aplicable?

Bloch menciona específicamente que la inmutable de las clases que tienen un control adecuado sobre sus casos puede garantizar a sus clientes que == es utilizable. enum menciona específicamente para ejemplificar.

Punto 1: Considerar métodos de fábrica estáticos en lugar de constructores

[...] permite una inmutable de la clase para hacer la garantía de que no hay dos iguales casos existen: a.equals(b) si y sólo si a==b. Si una clase que hace de esta garantía, entonces sus clientes pueden usar la == operador en lugar de la equals(Object) método, lo cual puede resultar en una mejora del rendimiento. Enumeración de los tipos de ofrecer esta garantía.

En resumen, los argumentos para el uso de == sobre enum son:

  • Funciona.
  • Es más rápido.
  • Es más seguro en tiempo de ejecución.
  • Es más seguro en tiempo de compilación.

88voto

Pascal Thivent Puntos 295221

Utilizando == comparar dos valores enum funciona porque hay solamente un objeto para cada constante de enumeración.

En una nota lateral, realmente no hay necesidad de usar == para escribir código seguro nulo si escribes tu equals() así:

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

Esta es una mejor práctica conocida como Comparar constantes desde la izquierda que definitivamente debe seguir.

58voto

Tobias Puntos 478

Como otros han dicho, == y .equals() de trabajo en la mayoría de los casos. El tiempo de compilación certeza de que no estás comparando completamente distintos tipos de Objetos que otros han señalado, es válido y beneficioso, sin embargo el tipo particular de error de comparar objetos de dos diferentes compilar los tipos de tiempo podría también ser encontrado por FindBugs (y probablemente por Eclipse/IntelliJ tiempo de compilación de inspección), de modo que el compilador de Java de encontrar no añadir que mucho de seguridad adicional.

Sin embargo:

  1. El hecho de que == nunca lanza NPE en mi mente es una desventaja de ==. No debiera ser nunca una necesidad para enum tipos null, ya que cualquier exceso de estado que desea expresar a través de null sólo puede ser agregado a la enum como una instancia adicional. Si es que inesperadamente null, prefiero tener un NPE que == silenciosamente evaluar a false. Por lo tanto, no estoy de acuerdo con el es más seguro en tiempo de ejecución de la opinión; es mejor conseguir en el hábito de no dejar que enum valores @Nullable.
  2. El argumento de que == es más rápido también es falso. En la mayoría de los casos vas a llamar a .equals() sobre una variable cuyo tiempo de compilación el tipo es la clase enum, y en esos casos, el compilador puede saber que este es el mismo como == (debido a un enums' equals() método no puede ser anulado) y puede optimizar la función de llamada de distancia. No estoy seguro de si el compilador en la actualidad hace esto, pero si no es así, y resulta ser un problema de rendimiento en Java en general, entonces prefiero arreglar el compilador que han de 100.000 los programadores de Java a cambiar su estilo de programación para adaptarse a una particular versión del compilador características de rendimiento.
  3. enums son Objetos. Para todos los demás tipos de Objeto de la comparación estándar es .equals(), no ==. Creo que es peligroso hacer una excepción para enums porque podría terminar accidentalmente comparar Objetos con == en lugar de equals(), especialmente si usted refactorizar un enum en una no-clase enum. En caso de una refactorización, la Que funciona el punto de arriba está mal. Saber que == es correcto, usted necesita saber que el valor en cuestión es un enum o un primitivo; si era un no-enum clase, que sería fácil perderse debido a que el código se compilará. En el caso de .equals(), el único caso en el que está mal es que si los valores en cuestión son primitivas; en ese caso, el código no compila y así es mucho más difícil perderse. Por lo tanto, .equals() es mucho más fácil identificar la correcta, y es más seguro contra futuros refactorings.

De hecho, pienso que el lenguaje Java debe tener definido == sobre los Objetos para llamar .igual() en el lado izquierdo de valor, y la introducción de un operador independiente de la identidad del objeto, pero esa no es la manera de Java estaba definido.

En resumen, aún creo que los argumentos en favor del uso de .equals() para enum tipos.

14voto

ChrisCantrell Puntos 828

Aquí es un crudo de cronometraje de la prueba para comparar los dos:

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());
    }   

}

Comentario fuera de los IFs de una en una. Aquí están los dos compara desde arriba en desmontado 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 primera (es igual a) realiza una llamada virtual y las pruebas de la devolución booleano de la pila. La segunda (==) compara el objeto de direcciones directamente desde la pila. En el primer caso hay más actividad.

Me encontré con esta prueba varias veces con ambos IFs de una en una. El "==" es ligeramente más rápido.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X