Comparing Java enum members: == or equals()?

2019-01-01 07:59发布

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?

标签: java enums
16条回答
一个人的天荒地老
2楼-- · 2019-01-01 08:00

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.

查看更多
初与友歌
3楼-- · 2019-01-01 08:06

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.

查看更多
泪湿衣
4楼-- · 2019-01-01 08:07

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() 
查看更多
还给你的自由
5楼-- · 2019-01-01 08:08

tl;dr

Another option is the Objects.equals utility method.

Objects.equals( thisEnum , thatEnum )

Objects.equals

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));
查看更多
人气声优
6楼-- · 2019-01-01 08:08

I would like to explicitly highlight this specific difference between the == operator and equals() method:

The equals() method is meant to check whether the contents of the object(s) the reference variable(s) involved refer(s) to are the same.

The == operator checks whether the reference variable(s) involved refer(s) to the same object.

It's up to the implementing class to provide this differentiation as needed by the application.

Otherwise the default behavior will be as provided by the Object class (in Java) where as explained in http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Object.html#equals(java.lang.Object):

The equals method for class Object implements the most discriminating possible equivalence relation on objects; that is, for any non-null reference values x and y, this method returns true if and only if x and y refer to the same object (x == y has the value true).

查看更多
不流泪的眼
7楼-- · 2019-01-01 08:11

Enum in the middle is a set of constant integers. "==" is just as valid and proper as if you compared two integers.

查看更多
登录 后发表回答