Is it OK to use == on enums in Java?
JavaSyntaxEnumsJava Problem Overview
Is it OK to use ==
on enums in Java, or do I need to use .equals()
? In my testing, ==
always works, but I'm not sure if I'm guaranteed of that. In particular, there is no .clone()
method on an enum, so I don't know if it is possible to get an enum for which .equals()
would return a different value than ==
.
For example, is this OK:
public int round(RoundingMode roundingMode) {
if(roundingMode == RoundingMode.HALF_UP) {
//do something
} else if (roundingMode == RoundingMode.HALF_EVEN) {
//do something
}
//etc
}
Or do I need to write it this way:
public int round(RoundingMode roundingMode) {
if(roundingMode.equals(RoundingMode.HALF_UP)) {
//do something
} else if (roundingMode.equals(RoundingMode.HALF_EVEN)) {
//do something
}
//etc
}
Java Solutions
Solution 1 - Java
Just my 2 cents: Here is the code for Enum.java, as published by Sun, and part of the JDK:
public abstract class Enum<E extends Enum<E>>
implements Comparable<E>, Serializable {
// [...]
/**
* Returns true if the specified object is equal to this
* enum constant.
*
* @param other the object to be compared for equality with this object.
* @return true if the specified object is equal to this
* enum constant.
*/
public final boolean equals(Object other) {
return this==other;
}
}
Solution 2 - Java
Yes, == is fine - there's guaranteed to be just a single reference for each value.
However, there's a better way of writing your round method:
public int round(RoundingMode roundingMode) {
switch (roundingMode) {
case HALF_UP:
//do something
break;
case HALF_EVEN:
//do something
break;
// etc
}
}
An even better way of doing it is to put the functionality within the enum itself, so you could just call roundingMode.round(someValue)
. This gets to the heart of Java enums - they're object-oriented enums, unlike the "named values" found elsewhere.
EDIT: The spec isn't very clear, but section 8.9 states:
> The body of an enum type may contain > enum constants. An enum constant > defines an instance of the enum type. > An enum type has no instances other > than those defined by its enum > constants.
Solution 3 - Java
Yes, it is as if you had created singleton instances for each value in the enum:
public abstract class RoundingMode { public static final RoundingMode HALF_UP = new RoundingMode(); public static final RoundingMode HALF_EVEN = new RoundingMode();private RoundingMode() { // private scope prevents any subtypes outside of this class } }
However, the enum
construct gives you various benefits:
- Each instance's toString() prints the name given in code.
- (As mentioned in another post,) a variable of the enum type can be compared against constants using the
switch-case
control structure. - All the values in the enumeration can be queried using the
values
field that is 'generated' for each enum type - Here's the big one w.r.t identity comparisons: enum values survive serialization without cloning.
RoundingMode original = RoundingMode.HALF_UP; assert (RoundingMode.HALF_UP == original); // passesByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(original); oos.flush();
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bais); RoundingMode deserialized = (RoundingMode) ois.readObject();
assert (RoundingMode.HALF_UP == deserialized); // fails assert (RoundingMode.HALF_EVEN == deserialized); // fails
You can address this issue without enum, using a technique that involves writeReplace
and readResolve
, (see http://java.sun.com/j2se/1.4.2/docs/api/java/io/Serializable.html)...
I guess the point is -- Java goes out of its way to allow you use enum values' identities for testing equality; it is an encouraged practice.
Solution 4 - Java
== compares the references of two objects. For enums, it is guaranteed that there will only be one instance, and therefore for any two enums that are the same, == will be true.
Reference:
http://www.ajaxonomy.com/2007/java/making-the-most-of-java-50-enum-tricks
(couldn't find anything in the Sun docs)
Solution 5 - Java
Here is some evil code you might find interesting. :D
public enum YesNo {YES, NO}
public static void main(String... args) throws Exception {
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
Unsafe unsafe = (Unsafe) field.get(null);
YesNo yesNo = (YesNo) unsafe.allocateInstance(YesNo.class);
Field name = Enum.class.getDeclaredField("name");
name.setAccessible(true);
name.set(yesNo, "YES");
Field ordinal = Enum.class.getDeclaredField("ordinal");
ordinal.setAccessible(true);
ordinal.set(yesNo, 0);
System.out.println("yesNo " + yesNo);
System.out.println("YesNo.YES.name().equals(yesNo.name()) "+YesNo.YES.name().equals(yesNo.name()));
System.out.println("YesNo.YES.ordinal() == yesNo.ordinal() "+(YesNo.YES.ordinal() == yesNo.ordinal()));
System.out.println("YesNo.YES.equals(yesNo) "+YesNo.YES.equals(yesNo));
System.out.println("YesNo.YES == yesNo " + (YesNo.YES == yesNo));
}
Solution 6 - Java
Enums are a great place to jam polymorphic code.
enum Rounding {
ROUND_UP {
public int round(double n) { ...; }
},
ROUND_DOWN {
public int round(double n) { ...; }
};
public abstract int round(double n);
}
int foo(Rounding roundMethod) {
return roundMethod.round(someCalculation());
}
int bar() {
return foo(Rounding.ROUND_UP);
}
Solution 7 - Java
Note that there is problem when transfering enum via RMI/IIOP. See this thread:
http://www.velocityreviews.com/forums/t390342-enum-equality.html
Solution 8 - Java
== is generally okay, and there are advantages to both == and .equals()
. I personally prefer to always use .equals()
when comparing Objects, including enum
s. See also this discussion:
https://stackoverflow.com/questions/1750435/comparing-java-enum-members-or-equals