Sé que las enumeraciones de Java se compilan en clases con constructores privados y un grupo de miembros estáticos públicos. Al comparar dos miembros de una enumeración dada, siempre he usado .equals()
, por ejemplo
public useEnums(SomeEnum a)
{
if(a.equals(SomeEnum.SOME_ENUM_VALUE))
{
...
}
...
}
Sin embargo, acabo de encontrar un código que usa el operador igual en ==
lugar de .equals ():
public useEnums2(SomeEnum a)
{
if(a == SomeEnum.SOME_ENUM_VALUE)
{
...
}
...
}
¿Qué operador es el que debería usar?
Respuestas:
Ambas son técnicamente correctas. Si observa el código fuente
.equals()
, simplemente difiere==
.Lo uso
==
, sin embargo, ya que será nulo seguro.fuente
.equals()
usarlo? Yo se que no.Se
==
puede utilizar enenum
?Sí: las enumeraciones tienen controles de instancia ajustados que le permiten usar
==
para comparar instancias. Aquí está la garantía proporcionada por la especificación del idioma (énfasis por mí):Esta garantía es lo suficientemente sólida como para que Josh Bloch recomiende que, si insiste en usar el patrón singleton, la mejor manera de implementarlo es usar un elemento único
enum
(consulte: Java 2nd Edition, elemento 3: aplicar la propiedad singleton con un constructor privado o un tipo de enumeración ; también seguridad de subprocesos en Singleton )¿Cuáles son las diferencias entre
==
yequals
?Como recordatorio, hay que decir que, en general,
==
NO es una alternativa viable paraequals
. Sin embargo, cuando es así (como conenum
), hay dos diferencias importantes a considerar:==
nunca tiraNullPointerException
==
está sujeto a verificación de compatibilidad de tipos en tiempo de compilación¿Debe
==
usarse cuando corresponda?Bloch menciona específicamente que las clases inmutables que tienen un control adecuado sobre sus instancias pueden garantizar a sus clientes que
==
es utilizable.enum
se menciona específicamente para ejemplificar.Para resumir, los argumentos para usar
==
enenum
son:fuente
Color nothing = null;
mi humilde opinión es un error y debe corregirse, su enumeración tiene dos valores, no tres ( vea el comentario de Tom Hawtin) 4. Es más seguro en tiempo de compilación : OK, peroequals
aún así volveríafalse
. Al final, yo no lo creo, prefieroequals()
para la lectura (ver el comentario de Kevin).foo.equals(bar)
es más fácil de leer quefoo == bar
Usar
==
para comparar dos valores de enumeración funciona, porque solo hay un objeto para cada constante de enumeración.En una nota al margen, en realidad no hay necesidad de usar
==
para escribir código nulo-seguro, si escribeequals()
así:Esta es una práctica recomendada conocida como Comparar constantes desde la izquierda que definitivamente debes seguir.
fuente
.equals()
ingiero valores de cadena, pero sigo pensando que es una forma horrible de escribir código nulo seguro. Prefiero tener un operador (o un método, pero sé que [objeto nulo] .equals nunca será nulo seguro en Java debido a cómo funciona el operador de punto) que siempre es nulo seguro, independientemente del orden en que se utiliza. Semánticamente, el operador "igual" siempre debe conmutar.?.
), continuaré usando esta práctica al comparar con constantes y, TBH, no me parece horrible, tal vez simplemente menos "natural".null
enumeración suele ser un error. ¡Tienes esta enumeración de todos los valores posibles, y aquí hay otro!@Nullable
, considero que Comparar constantes desde la izquierda es un antipatrón porque propaga la ambigüedad sobre qué valores pueden o no ser nulos. Los tipos de enumeración casi nunca deberían existir@Nullable
, por lo que un valor nulo sería un error de programación; en tal caso, cuanto antes arroje NPE, más probable será que encuentre su error de programación donde permitió que sea nulo. Entonces, "la mejor práctica ... que definitivamente debes seguir" es completamente errónea cuando se trata de tipos de enumeración.Como han dicho otros, tanto
==
y.equals()
de trabajo en la mayoría de los casos. La certeza de tiempo de compilación de que no está comparando tipos completamente diferentes de Objetos que otros han señalado es válida y beneficiosa, sin embargo, FindBugs también encontraría el tipo particular de error de comparar objetos de dos tipos de tiempo de compilación diferentes (y probablemente por Eclipse / IntelliJ inspecciones de tiempo de compilación), por lo que el compilador de Java al encontrarlo no agrega tanta seguridad adicional.Sin embargo:
==
nunca tira NPE en mi mente es una desventaja de==
. Casi nunca debería existir la necesidad deenum
quenull
existan tipos , ya que cualquier estado adicional que desee expresar a través de élnull
puede agregarseenum
como una instancia adicional. Si es inesperadonull
, prefiero tener un NPE que==
evaluar en silencio a falso. Por lo tanto, no estoy de acuerdo con la opinión más segura en tiempo de ejecución ; es mejor acostumbrarse a nunca dejar que losenum
valores sean@Nullable
.==
es más rápido también es falso. En la mayoría de los casos se le llama.equals()
en una variable cuyo tipo de tiempo de compilación es la clase de enumeración, y en esos casos el compilador puede saber que esto es lo mismo que==
(debido a unaenum
'sequals()
método no puede ser anulado) y se puede optimizar la función de llamada lejos. No estoy seguro de si el compilador actualmente hace esto, pero si no lo hace, y resulta ser un problema de rendimiento en Java en general, prefiero arreglar el compilador antes de que 100,000 programadores de Java cambien su estilo de programación para adaptarse características de rendimiento de una versión de compilador particular.enums
son objetos Para todos los demás tipos de Objetos, la comparación estándar es.equals()
, no==
. Creo que es peligroso hacer una excepciónenums
porque podría terminar comparando accidentalmente objetos con en==
lugar deequals()
, especialmente si refactoriza unaenum
clase que no es enum. En caso de tal refactorización, el punto Funciona desde arriba es incorrecto. Para convencerse de que el uso de==
es correcto, debe verificar si el valor en cuestión esenum
primitivo o no; si no fuera deenum
clase, sería incorrecto pero fácil de perder porque el código aún se compilaría. El único caso cuando un uso de.equals()
estaría mal si los valores en cuestión fueran primitivos; en ese caso, el código no se compilaría, por lo que es mucho más difícil pasarlo por alto. Por lo tanto,.equals()
es mucho más fácil de identificar como correcto y es más seguro contra futuras refactorizaciones.De hecho, creo que el lenguaje Java debería haber definido == en Objetos para llamar a .equals () en el valor de la izquierda e introducir un operador separado para la identidad del objeto, pero no es así como se definió Java.
En resumen, sigo pensando que los argumentos están a favor del uso
.equals()
deenum
tipos.fuente
enum
comoswitch
objetivo, por lo que son un poco especiales.String
s son un poco especiales también.Prefiero usar en
==
lugar deequals
:Otra razón, además de las otras ya discutidas aquí, es que podría introducir un error sin darse cuenta. Supongamos que tiene estas enumeraciones que son exactamente iguales pero en paquetes separados (no es común, pero podría suceder):
Primera enumeración :
Segunda enumeración:
Luego, suponga que usa los iguales como next en el
item.category
que estáfirst.pckg.Category
pero importa el segundo enum (second.pckg.Category
) en lugar del primero sin darse cuenta:Así que siempre obtendrás
false
una enumeración diferente, aunque esperas cierto porqueitem.getCategory()
es asíJAZZ
. Y podría ser un poco difícil de ver.Entonces, si en su lugar usa el operador
==
, tendrá un error de compilación:fuente
Aquí hay una prueba cruda de tiempo para comparar los dos:
Comente los IF uno por uno. Aquí están las dos comparaciones de arriba en código de byte desmontado:
El primero (igual) realiza una llamada virtual y prueba el valor booleano de retorno de la pila. El segundo (==) compara las direcciones de los objetos directamente desde la pila. En el primer caso hay más actividad.
Ejecuté esta prueba varias veces con ambos IF uno a la vez. El "==" es un poco más rápido.
fuente
¡En caso de enumeración, ambos son correctos y correctos!
fuente
tl; dr
Otra opción es el
Objects.equals
método de utilidad.Objects.equals
para seguridad nulaUna tercera opción es el
equals
método estático que se encuentra en laObjects
clase de utilidad agregada a Java 7 y versiones posteriores.Ejemplo
Aquí hay un ejemplo usando la
Month
enumeración.Beneficios
Encuentro un par de beneficios para este método:
true
false
NullPointerException
Cómo funciona
¿Cuál es la lógica utilizada por
Objects.equals
?Véalo usted mismo, del código fuente de Java 10 de OpenJDK :
fuente
Usar cualquier otra cosa que no sea
==
comparar constantes enum no tiene sentido. Es como compararclass
objetos conequals
, ¡no lo hagas!Sin embargo, hubo un error desagradable (BugId 6277781 ) en Sun JDK 6u10 y anteriores que podría ser interesante por razones históricas. Este error evitó el uso adecuado de las
==
enumeraciones deserializadas, aunque esto podría decirse que es un caso de esquina.fuente
Las enumeraciones son clases que devuelven una instancia (como singletons) para cada constante de enumeración declarada por
public static final field
(inmutable) para que el==
operador pueda usarse para verificar su igualdad en lugar de usar elequals()
métodofuente
La razón por la que las enumeraciones funcionan fácilmente con == es porque cada instancia definida también es un singleton. Entonces la comparación de identidad usando == siempre funcionará.
Pero usar == porque funciona con enumeraciones significa que todo su código está estrechamente relacionado con el uso de esa enumeración.
Por ejemplo: las enumeraciones pueden implementar una interfaz. Suponga que actualmente está utilizando una enumeración que implementa Interface1. Si más adelante, alguien lo cambia o introduce una nueva clase Impl1 como implementación de la misma interfaz. Luego, si comienza a usar instancias de Impl1, tendrá mucho código para cambiar y probar debido al uso previo de ==.
Por lo tanto, es mejor seguir lo que se considera una buena práctica a menos que haya una ganancia justificable.
fuente
Una de las reglas de Sonar es
Enum values should be compared with "=="
. Las razones son las siguientes:Por último, pero no menos importante, las
==
enumeraciones on son posiblemente más legibles (menos detalladas) queequals()
.fuente
En resumen, ambos tienen pros y contras.
Por un lado, tiene ventajas para usar
==
, como se describe en las otras respuestas.Por otro lado, si por alguna razón reemplaza las enumeraciones con un enfoque diferente (instancias de clase normales), habiendo usado
==
picaduras. (BTDT.)fuente
Quiero complementar la respuesta de polygenelubricants:
Personalmente prefiero igual (). Pero tiene el control de compatibilidad de tipos. Lo cual creo que es una limitación importante.
Para comprobar la compatibilidad de tipos en el momento de la compilación, declare y use una función personalizada en su enumeración.
Con esto, tiene todas las ventajas de ambas soluciones: protección NPE, código fácil de leer y verificación de compatibilidad de tipos en el momento de la compilación.
También recomiendo agregar un valor INDEFINIDO para enum.
fuente
==
? Con==
usted obtiene protección NPE, código fácil de leer y compilación de verificación de compatibilidad de tipo de tiempo, y obtiene todo eso sin escribir ningún método personalizado similar a igual.UNDEFINED
valor es probablemente una buena idea. Por supuesto, en Java 8 usarías unOptional
lugar.