Comparing Java enum members: == or equals()?
Asked Answered
C

15

2178

I know that Java enums are compiled to classes with private constructors and a bunch of public static members. When comparing two members of a given enum, I've always used .equals(), e.g.

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

However, I just came across some code that uses the equals operator == instead of .equals():

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

Which operator is the one I should be using?

Conformation answered 17/11, 2009 at 17:26 Comment(3)
I just stumbled across a very similar question: #534422Conformation
I'm surprised that in all the answers (especially the one from polygenelubricants which explains in detail why == works) that another big benefit of == wasn't mentioned: that it makes explicit how enums work (as a fixed set of singleton objects). With equals it leads one to think that there can somehow be multiple instances of the same enum 'alternative' floating around.Arkansas
SomeEnum.SOME_ENUM_VALUE.equals(a) never throws NullPointerException while a.equals(SomeEnum.SOME_ENUM_VALUE) might.Deliver
W
2019

Both are technically correct. If you look at the source code for .equals(), it simply defers to ==.

I use ==, however, as that will be null safe.

Wearproof answered 17/11, 2009 at 17:29 Comment(3)
another argument to use == instead of equals ist compile-time checking of types. myEnum.MY_CONSTANT.equals("Some String") will compile and myEnum.MY_CONSTANT == "Some String" will not, as "Some String" is not of the same type and the compiler can determin it upfrontUnblessed
I'd also add that == is safe with respect to NPE. If for example we invoke equals on a nullable type we can incur in a NPE nullableMyEnum.equals(MyEnum.CONST).Scurry
For that, you can always invert the condition: MyEnum.CONST.equals(nullableMyEnum)Crier
A
1358

Can == be used on enum?

Yes: enums have tight instance controls that allows you to use == to compare instances. Here's the guarantee provided by the language specification (emphasis by me):

JLS 8.9 Enums

An enum type has no instances other than those defined by its enum constants.

It is a compile-time error to attempt to explicitly instantiate an enum type. The final clone method in Enum ensures that enum constants can never be cloned, and the special treatment by the serialization mechanism ensures that duplicate instances are never created as a result of deserialization. Reflective instantiation of enum types is prohibited. Together, these four things ensure that no instances of an enum type exist beyond those defined by the enum constants.

Because there is only one instance of each enum constant, it is permissible to use the == operator in place of the equals method when comparing two object references if it is known that at least one of them refers to an enum constant. (The equals method in Enum is a final method that merely invokes super.equals on its argument and returns the result, thus performing an identity comparison.)

This guarantee is strong enough that Josh Bloch recommends, that if you insist on using the singleton pattern, the best way to implement it is to use a single-element enum (see: Effective Java 2nd Edition, Item 3: Enforce the singleton property with a private constructor or an enum type; also Thread safety in Singleton)


What are the differences between == and equals?

As a reminder, it needs to be said that generally, == is NOT a viable alternative to equals. When it is, however (such as with enum), there are two important differences to consider:

== never throws NullPointerException

enum Color { BLACK, WHITE };

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

== is subject to type compatibility check at compile time

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!

Should == be used when applicable?

Bloch specifically mentions that immutable classes that have proper control over their instances can guarantee to their clients that == is usable. enum is specifically mentioned to exemplify.

Item 1: Consider static factory methods instead of constructors

[...] it allows an immutable class to make the guarantee that no two equal instances exist: a.equals(b) if and only if a==b. If a class makes this guarantee, then its clients can use the == operator instead of the equals(Object) method, which may result in improved performance. Enum types provide this guarantee.

To summarize, the arguments for using == on enum are:

  • It works.
  • It's faster.
  • It's safer at run-time.
  • It's safer at compile-time.
Atween answered 30/5, 2010 at 4:38 Comment(0)
T
122

Using == to compare two enum values works, because there is only one object for each enum constant.

On a side note, there is actually no need to use == to write null-safe code, if you write your equals() like this:

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

This is a best practice known as Compare Constants From The Left that you definitely should follow.

Tamarin answered 17/11, 2009 at 17:30 Comment(3)
A null enum is typically an error. You've got this enumeration of all possible values, and here's another one!Godsend
Compare Constants From The Left a best practice like Yoda style best English is.Connecticut
Lol. When 900 years old you become, look this good your boolean comparisons will not, hmmmm? It may be less natural, but the answer is correct in that it saves you from null checks, which makes it more readable than using the constant on the right. That said, with enums & constants, == is the most readable option, as the answer points out.Leo
K
73

As others have said, both == and .equals() work in most cases. The compile time certainty that you're not comparing completely different types of Objects that others have pointed out is valid and beneficial, however the particular kind of bug of comparing objects of two different compile time types would also be found by FindBugs (and probably by Eclipse/IntelliJ compile time inspections), so the Java compiler finding it doesn't add that much extra safety.

However:

  1. The fact that == never throws NPE in my mind is a disadvantage of ==. There should hardly ever be a need for enum types to be null, since any extra state that you may want to express via null can just be added to the enum as an additional instance. If it is unexpectedly null, I'd rather have a NPE than == silently evaluating to false. Therefore I disagree with the it's safer at run-time opinion; it's better to get into the habit never to let enum values be @Nullable.
  2. The argument that == is faster is also bogus. In most cases you'll call .equals() on a variable whose compile time type is the enum class, and in those cases the compiler can know that this is the same as == (because an enum's equals() method can not be overridden) and can optimize the function call away. I'm not sure if the compiler currently does this, but if it doesn't, and turns out to be a performance problem in Java overall, then I'd rather fix the compiler than have 100,000 Java programmers change their programming style to suit a particular compiler version's performance characteristics.
  3. enums are Objects. For all other Object types the standard comparison is .equals(), not ==. I think it's dangerous to make an exception for enums because you might end up accidentally comparing Objects with == instead of equals(), especially if you refactor an enum into a non-enum class. In case of such a refactoring, the It works point from above is wrong. To convince yourself that a use of == is correct, you need to check whether value in question is either an enum or a primitive; if it was a non-enum class, it'd be wrong but easy to miss because the code would still compile. The only case when a use of .equals() would be wrong is if the values in question were primitives; in that case, the code wouldn't compile so it's much harder to miss. Hence, .equals() is much easier to identify as correct, and is safer against future refactorings.

I actually think that the Java language should have defined == on Objects to call .equals() on the left hand value, and introduce a separate operator for object identity, but that's not how Java was defined.

In summary, I still think the arguments are in favor of using .equals() for enum types.

Kavanaugh answered 14/2, 2013 at 11:59 Comment(0)
V
29

I prefer to use == instead of equals:

Other reason, in addition to the others already discussed here, is you could introduce a bug without realizing it. Suppose you have this enums which is exactly the same but in separated pacakges (it's not common, but it could happen):

First enum:

package first.pckg

public enum Category {
    JAZZ,
    ROCK,
    POP,
    POP_ROCK
}

Second enum:

package second.pckg

public enum Category {
    JAZZ,
    ROCK,
    POP,
    POP_ROCK
}

Then suppose you use the equals like next in item.category which is first.pckg.Category but you import the second enum (second.pckg.Category) instead the first without realizing it:

import second.pckg.Category;
...

Category.JAZZ.equals(item.getCategory())

So you will get allways false due is a different enum although you expect true because item.getCategory() is JAZZ. And it could be be a bit difficult to see.

So, if you instead use the operator == you will have a compilation error:

operator == cannot be applied to "second.pckg.Category", "first.pckg.Category"

import second.pckg.Category; 
...

Category.JAZZ == item.getCategory() 
Voyeur answered 21/4, 2017 at 6:47 Comment(1)
This is an important check, worth to mentionSupinator
P
24

tl;dr

Another option is the Objects.equals utility method.

Objects.equals( thisEnum , thatEnum )

Objects.equals for null-safety

equals operator == instead of .equals()

Which operator is the one I should be using?

A third option is the static equals method found on the Objects utility class added to Java 7 and later.

Example

Here’s an example using the Month enum.

boolean areEqual = Objects.equals( Month.FEBRUARY , Month.JUNE ) ;  // Returns `false`.

Benefits

I find a couple benefits to this method:

  • Null-safety
  • Compact, readable

How it works

What is the logic used by Objects.equals?

See for yourself, from the Java 10 source code of OpenJDK:

return 
    ( a == b ) 
    || 
    ( 
        a != null 
        && 
        a.equals( b )
    )
;
Pantaloon answered 29/10, 2018 at 3:13 Comment(2)
non of the benefits you stated is true for Objects.equals vs ==. == behaves exactly the same as Objects.equals in the mentioned scenarios.Phonoscope
Do you know how to null-safe invoke Enum.compareTo() here? Objects.compare() requires a Comparator for this.Unmade
J
18

One of the Sonar rules is Enum values should be compared with "==". The reasons are as follows:

Testing equality of an enum value with equals() is perfectly valid because an enum is an Object and every Java developer knows == should not be used to compare the content of an Object. At the same time, using == on enums:

  • provides the same expected comparison (content) as equals()

  • is more null-safe than equals()

  • provides compile-time (static) checking rather than runtime checking

For these reasons, use of == should be preferred to equals().

Last but not least, the == on enums is arguably more readable (less verbose) than equals().

Jolynnjon answered 29/3, 2020 at 7:5 Comment(0)
T
16

Here is a crude timing test to compare the two:

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

}

Comment out the IFs one at a time. Here are the two compares from above in disassembled 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

The first (equals) performs a virtual call and tests the return boolean from the stack. The second (==) compares the object addresses directly from the stack. In the first case there is more activity.

I ran this test several times with both IFs one at a time. The "==" is ever so slightly faster.

Tense answered 14/10, 2011 at 21:19 Comment(0)
J
11

In case of enum both are correct and right!!

Jehovist answered 17/11, 2009 at 17:28 Comment(0)
A
9

Using anything other than == to compare enum constants is nonsense. It's like comparing class objects with equals – don't do it!

However, there was a nasty bug (BugId 6277781) in Sun JDK 6u10 and earlier that might be interesting for historical reasons. This bug prevented proper use of == on deserialized enums, although this is arguably somewhat of a corner case.

Approver answered 26/10, 2015 at 20:40 Comment(2)
Corner case for you, every day case for million others. Using == and .equals() is both valid.Betook
@AndrejBuday Please read the source code for equals() in java.lang.Enum before you post patronizing nonsense.Approver
I
7

Enums are classes that return one instance (like singletons) for each enumeration constant declared by public static final field (immutable) so that == operator could be used to check their equality rather than using equals() method

Implacable answered 7/11, 2015 at 15:21 Comment(0)
C
5

Just one thing to add to all the other excellent answers. When you use a simple lambda I do prefer equals over ==, because you can use method referencing.

Consider following lambdas:

Stream.of(SomeEnum.A, SomeEnum.B).anyMatch(e -> e == SomeEnum.B);
Stream.of(SomeEnum.A, SomeEnum.B).anyMatch(e -> e.equals(SomeEnum.B));

The later can be converted to:

Stream.of(SomeEnum.A, SomeEnum.B).anyMatch(SomeEnum.B::equals));
Chuch answered 17/9, 2021 at 7:15 Comment(0)
T
2

The reason enums work easily with == is because each defined instance is also a singleton. So identity comparison using == will always work.

But using == because it works with enums means all your code is tightly coupled with usage of that enum.

For example: Enums can implement an interface. Suppose you are currently using an enum which implements Interface1. If later on, someone changes it or introduces a new class Impl1 as an implementation of same interface. Then, if you start using instances of Impl1, you'll have a lot of code to change and test because of previous usage of ==.

Hence, it's best to follow what is deemed a good practice unless there is any justifiable gain.

Traveler answered 12/12, 2017 at 3:19 Comment(0)
L
-1

I want to complement polygenelubricants answer:

I personally prefer equals(). But it lake the type compatibility check. Which I think is an important limitation.

To have type compatibility check at compilation time, declare and use a custom function in your enum.

public boolean isEquals(enumVariable) // compare constant from left
public static boolean areEqual(enumVariable, enumVariable2) // compare two variable

With this, you got all the advantage of both solution: NPE protection, easy to read code and type compatibility check at compilation time.

I also recommend to add an UNDEFINED value for enum.

Lat answered 17/10, 2014 at 8:43 Comment(1)
Why is this solution any better than ==? With == you get NPE protection, easy-to-read code, and compile time type compatibility checking, and you get all of those without writing any custom equals-like methods.Conformation
C
-1

In short, both have pros and cons.

On one hand, it has advantages to use ==, as described in the other answers.

On the other hand, if you for any reason replace the enums with a different approach (normal class instances), having used == bites you. (BTDT.)

Compiler answered 4/6, 2017 at 10:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.