tags:

views:

1830

answers:

5

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 come code that uses the equals operator == instead:

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

I've been programming in Java for 5+ years, and I thought I understood difference between the two - but I'm still scratching my head at which one is more correct. Which operator is the one I should be using?

+2  A: 

In case of enum both are correct and right!!

Suraj Chandran
+19  A: 

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

Milan Ramaiya
Personally, I dont like 'null safety' mentioned as a reason to use ==.
Nivas
I second that answer, for the tiny improvement in runtime performance too.
Carl Smotricz
@Nivas: why not? Do you like worrying about the order of your arguments (which only applies to comparing constants from the left, as in Pascal's answer)? Do you like always checking that a value is not null before `.equals()`ing it? I know I don't.
Matt Ball
@Carl Smotricz, equals will most likely be inlined by the JIT, so performance isn't an issue
Steve Kuo
Keep in mind that when reading your code, the "==" may appear incorrect to the reader until he/she goes off and looks at the source for the type involved, then sees it's an enum. In that sense, it's less distracting to read ".equals()".
Kevin Bourrillion
@Kevin - if you're not using an IDE that allows you to see types directly when viewing the source, you're cheating yourself - not an issue with a proper IDE.
MetroidFan2002
+9  A: 

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(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.

Pascal Thivent
Exactly - this is the whole point of using enum.
Grandpa
I do this when `.equals()`ing string values, but I still think that it's a crappy way to write null-safe code. I'd much rather have an operator (or a method, but I know that [null object].equals won't ever be null-safe in Java because of how the dot operator works) that's always null-safe, regardless of the order it's used in. Semantically, the "equals" operator should *always* commute.
Matt Ball
Well, as Java doesn't have the Safe Navigation operator of Groovy (`?.`), I'll continue to use this practice when comparing to constants and, TBH, I don't find it crappy, maybe just less "natural".
Pascal Thivent
A `null` enum is typically an error. You've got this enumeration of all possible values, and here's another one!
Tom Hawtin - tackline
A: 

You may prefer using the == sign. Check this blog post: == or equals with Java enum

Abel Morelos
The blog doesn't say that.
BalusC
That blog post says its better to use reference equality for enums.
Milan Ramaiya
Sorry guys, I meant the oppositive, I just corrected my answer.
Abel Morelos
Well, as the post mentions, there are two cases to consider, either reference equality or logical equality, you need to decide by yourself what you want to do.
Abel Morelos
Except for enums, equals() simply calls ==, so there is no difference except one isn't null safe.
Milan Ramaiya
enums should always be == since == and .equals are the same for them. The issue with the .equals in the blog is that it will compile but always return false which is pointless whereas the == will fail at compile time.
TofuBeer
@Abel: I read that blog post before asking my question here. It was useless.
Matt Ball
I disagree with the blog in general. It makes generalizations that equals is preferred over ==. This is false, it's depends on the context of the compare. Also the .NET style naming conventions are annoying (EState, ILamp).
Steve Kuo
+8  A: 

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:

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.
polygenelubricants
Nice answer but... 1. *It works* : agreed 2. *it's faster* : prove it for enums :) 3. *It's safer at run-time* : `Color nothing = null;` is IMHO a bug and should be fixed, your enum has two values, not three (see Tom Hawtin's comment) 4. *It's safer at compile-time* : OK, but `equals` would still return `false`. At the end, *I* don't buy it, I prefer `equals()` for the readability (see Kevin's comment).
Pascal Thivent
@Pascal: I agree that the `null` argument is weak, because `null` is controversial to begin with (C.A.R. Hoare "billion dollar mistake" etc). See also my question: http://stackoverflow.com/questions/2887761/is-it-a-bad-idea-if-equalsnull-throws-nullpointerexception-instead // I do think the compile-time type compatibility check is significant and is much better than "silently failing" at run-time by returning `false`. I'm actually not concerned with speed advantage since it's not likely to be significant; I'm merely repeating what Bloch said.
polygenelubricants
I admit my own argument "against" the compile-time check is also weak (and compile-time check is actually probably the best argument for `==` even if "silently fail" seems too strong to me). Regarding Bloch's point about speed, I'm of course not saying he's wrong, I'm just not convinced it applies for enums (and he wrote *may*). That's why I thought it was legitimate to challenge your pros a bit :) But you have my +1, it's still a nice answer.
Pascal Thivent