Is it OK to use == on enums in Java?

JavaSyntaxEnums

Java 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.
The serialization is a big gotchya. If I were to use the code above instead of an enum, here's how identity equality would behave:
RoundingMode original = RoundingMode.HALF_UP;
assert (RoundingMode.HALF_UP == original); // passes

ByteArrayOutputStream 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 enums. See also this discussion:

https://stackoverflow.com/questions/1750435/comparing-java-enum-members-or-equals

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionKipView Question on Stackoverflow
Solution 1 - JavaVarkhanView Answer on Stackoverflow
Solution 2 - JavaJon SkeetView Answer on Stackoverflow
Solution 3 - JavaDilum RanatungaView Answer on Stackoverflow
Solution 4 - JavalevandView Answer on Stackoverflow
Solution 5 - JavaPeter LawreyView Answer on Stackoverflow
Solution 6 - JavapaulmurrayView Answer on Stackoverflow
Solution 7 - JavajohnyView Answer on Stackoverflow
Solution 8 - JavaTobiasView Answer on Stackoverflow