tags:

views:

640

answers:

3

Why does the following code fail to compile, while changing the case statement to

case ENUM1: doSomeStuff();

works?

public enum EnumType
{
    ENUM1, ENUM2, ENUM3;

    void doSomeStuff()
    {
        switch(this)
        {
        case EnumType.ENUM1: doSomeStuff();
        }
    }
}
+6  A: 

This is to avoid the ability to compare against different enum types. It makes sense to restrict it to one type, i.e. the type of the enum value in the switch statement.

Update: it's actually to keep binary compatibility. Here's a cite from about halfway chapter 13.4.9 of JLS:

One reason for requiring inlining of constants is that switch statements require constants on each case, and no two such constant values may be the same. The compiler checks for duplicate constant values in a switch statement at compile time; the class file format does not do symbolic linkage of case values.

In other words, because of the class identifier in EnumType.ENUM1, it cannot be represented as a compiletime constant expression, while it is required by the switch statement.

BalusC
Hmm... I am not 100% convinced. To `OtherEnumType.ENUM1` the (Eclipse) compiler gives `Type mismatch: cannot convert from OtherEnumType to EnumType`, while to `EnumType.ENUM1` it gives `The qualified case label EnumType.ENUM1 must be replaced with the unqualified enum constant ENUM1`. So to me it seems that prohibiting the type qualifier is not related to detecting type mismatch.
Péter Török
I like it! Nice find.
maleki
+3  A: 

Since you're switching on an object of type EnumType and the only possible values for it are the enum constants, there's no need to qualify those constants again in within the switch. After all, it would be illegal to have case OtherEnumType.ENUM1: in it anyway.

ColinD
I think this might be the exact case. Trying to use an enum from OtherEnumType by using "case enum:" instead of "case OtherEnumType.enum" gives an error close to what you described.
maleki
+2  A: 

This is not really answering your question but if you have code depending on the enum value, you can also create an abstract method in your enum that gets overloaded for every value:

public enum EnumType {
    ENUM1 {
        @Override
        public void doSomeStuff() {
            // do something
        }
    },
    ENUM2 {
        @Override
        public void doSomeStuff() {
            // do something else
        }
    };

    public abstract void doSomeStuff();
}
Jörn Horstmann
Best answer +1. This technique provides superior safety when adding new values, because you *can't* forget to add the method implementation compared to missing a case statement.
Willi
Hint: No need to make doSomeStuff abstract if you can provide a meaningful default implementation.
Willi