399

First I'll state that I'm much more familiar with enums in C# and it seems like enums in java is a quite mess.

As you can see, I'm trying to use a switch statement @ enums in my next example but I always get an error no matter what I'm doing.

The error I receive is:

The qualified case label SomeClass.AnotherClass.MyEnum.VALUE_A must be replaced with the unqualified enum constant VALUE_A

The thing is I quite understand the error but I can't just write the VALUE_A since the enum is located in another sub-class. Is there a way to solve this problem? And why is it happening in Java?

//Main Class
public class SomeClass {

    //Sub-Class
    public static class AnotherClass {
        public enum MyEnum {
            VALUE_A, VALUE_B
        }    
        public MyEnum myEnum;
    }

    public void someMethod() { 
        MyEnum enumExample //...

        switch (enumExample) {
            case AnotherClass.MyEnum.VALUE_A: { <-- error on this line
                //..
                break;
            }
        }
    }
}
rink.attendant.6
  • 44,500
  • 61
  • 101
  • 156
Popokoko
  • 6,413
  • 16
  • 47
  • 58
  • As darrengorman commented, Java [`Enum`](http://docs.oracle.com/javase/8/docs/api/java/lang/Enum.html) are *extremely* handy once you get the hang of them – not at all a mess. They are much more flexible and practical than simple enums (merely a labeled integer value) as seen on other platforms. See the [Oracle Tutorial](http://docs.oracle.com/javase/tutorial/java/javaOO/enum.html). Discover the optimized `Set`/`Map` implementations: [`EnumSet`](http://docs.oracle.com/javase/8/docs/api/java/util/EnumSet.html) & [`EnumMap`](http://docs.oracle.com/javase/8/docs/api/java/util/EnumMap.html). – Basil Bourque Aug 05 '17 at 20:12
  • 2
    When you try to qualify the case statement; in a way, you are trying to say that I can mix different types of enums (not just same enum type) within a single switch statement. Java has stopped it with this approach as discussed here http://www.digizol.com/2010/10/enum-case-label-switch-java-qualified.html – lkamal Nov 16 '17 at 18:52
  • This happened to me while refactoring (moving) a class in IntelliJ 2018.2 – Daniel Alder Jul 29 '19 at 08:28

8 Answers8

783

Change it to this:

switch (enumExample) {
    case VALUE_A: {
        //..
        break;
    }
}

The clue is in the error. You don't need to qualify case labels with the enum type, just its value.

darrengorman
  • 12,952
  • 2
  • 23
  • 24
  • 24
    Ok i feel so stupid :-( You are totally right, i was convinced i tried this exact line and got an error with that so i moved to qualify case, but your suggestion DOES work. – Popokoko Apr 15 '12 at 11:09
  • 5
    By the way I think you'll find that enums in Java are incredibly useful once you start to use them more, I wouldn't say they're a mess at all :) – darrengorman Apr 15 '12 at 11:17
  • 1
    I believe i will find you are right in the close future :) Anyway, this is definitely the best programming forum around thanks to people like you. – Popokoko Apr 15 '12 at 11:20
  • 22
    @milkplusvellocet, I know this post is already old, but I'm curious why Java don't allow the **qualified case label** in the switch statement? – jjz Dec 06 '13 at 17:43
  • 5
    @cRane01 don't know for sure, but it makes for a cleaner syntax. Specifying the type on each case would be totally redundant – darrengorman Dec 09 '13 at 10:28
  • 1
    What about if you have another constant called the same thing in another class? Wouldn't `VALUE_A` be ambiguous in that case? – HelloGoodbye Sep 07 '14 at 10:52
  • 4
    @HelloGoodbye No. The switch statement's variable defines the type of the case statement so it can only be one enum. – sprinter Dec 23 '15 at 01:49
  • Question: Let's say I have: `enum AnimalType { Fish, Horse }`. I have a parameter `AnimalType a` in a function with the statement: `switch(myAnimal.getType())` and then `case a` in that. I get the error, what to do? – JakeTheSnake Nov 16 '16 at 21:41
  • 4
    Upvoted this answer already back in 2015 .. here we go again :D Still don't understand why a qualified name is a compiler error. Like, if it's ugly and redundant, so be it, that's on my shoulders. My IDE can tell me that it's unnecessary, but crashing the compiling? I don't know ... Seems odd to me at least, and therefore unintuitive. – BAERUS Feb 01 '21 at 07:52
  • This is slightly counter-intuitive but solved my issue too. When you have a slow build for a large system (made worse by gradle) and have to upgrade a library due to a CVE security flaw urgently, this compile error costs me a lot of valuable time. – Sridhar Sarnobat Mar 12 '21 at 19:47
63

Wrong:

case AnotherClass.MyEnum.VALUE_A

Right:

case VALUE_A:
Pika Supports Ukraine
  • 3,612
  • 10
  • 26
  • 42
Akash Yellappa
  • 2,126
  • 28
  • 21
44

Java infers automatically the type of the elements in case, so the labels must be unqualified.

int i;
switch(i) {
   case 5: // <- integer is expected
}
MyEnum e;
switch (e) {
   case VALUE_A: // <- an element of the enumeration is expected
}
Kru
  • 4,195
  • 24
  • 31
  • 28
    Why _must_ it be unqualified? – Thorbjørn Ravn Andersen Aug 19 '15 at 13:25
  • 13
    If you could qualify, then you might use something else than `MyEnum` which would not make sense. – Kru Aug 31 '15 at 18:03
  • 2
    @Kru, but I **can** use something grammatically-else for non-enum-typed case expressions. E.g. `static final int MY_CONST = 7; …; switch(intVariable) {case MY_CONST: …;}` instead of `case 7`. So this restriction for enums makes **no** sense (I can use not only primary literals, but also manually-defined constants for integer `switch` expression, but I can't use manually-defined constants, but only primary names for enums). – Sasha Nov 15 '17 at 11:44
  • @Sasha enums in Java don't have integers assigned to them like in C++. They are abstract just like java boolean. – user13947194 Jul 31 '21 at 15:59
  • @user13947194, nobody said they have. I just pointed out the logical fallacy: for one type we can use both the primary literals and the manually-defined constants while for the other type we can use only primary names but not manually-defined constants. – Sasha Jan 15 '22 at 14:27
  • @Sasha I don't understand what you are talking about. Java enums are not associated with an integer and can't be associated with an integer. They can only be referenced by their name. – user13947194 Jan 15 '22 at 18:07
  • @user13947194, “They [enum values] can only be referenced by their name” — nope. We can create aliases for enum values — `static final MyEnumType aliasToEnumValue = MyEnumType.VALUE_A`; as well as we can create aliases for integer values — `static final int aliasToIntValue = 12`. But the design flaw is that only the latter (`case aliasToIntValue`) can be used a case label but not the former (`case aliasToEnumValue`). (As for “Java enums are not associated with an integer and can't be associated with an integer” — please don't argue with the statements that I have never expressed.) – Sasha Jan 20 '22 at 07:37
  • @Sasha now I understand you. I think enums in Java are Objects, and when you apply final to Objects you only have a const pointer and not a const Object. int on the other hand is a primitive. Applying final to int makes the value itself const. Another thing is, you probably dont need to do this, and Java is the type of parent to push you in the "right" direction. – user13947194 Jan 21 '22 at 21:49
  • @user13947194, "when you apply final to Objects you only have a const pointer and not a const Object" — that doesn't matter whether the object itself is const or not, because: (1) `const final myAlias = MyEnumType.VALUE_E` copies only the pointer; (2) `switch (myEnumValue) {…}` compares only the pointer. So fields in `MyEnumType` (if there are any) are irrelevant here. So, handling of enums and ints/chars is identical here (but syntax is different and that's weird). "you probably dont need". Of course, I need. – Sasha Jan 22 '22 at 06:49
  • My philosophy is: every logical inconsistency (including syntactic ones) may bite, sooner or later. Even if a specific one haven't bitten somebody yet, that doesn't mean it will never do that. – Sasha Jan 22 '22 at 07:02
  • @Sasha I don't know how you reckon that switch(myEnumValue) compares only the pointer. If that were the case, two enum objects of the same value would not compare equal. – user13947194 Jan 23 '22 at 04:23
  • @user13947194, can you please provide an example of what you mean by "two enum objects of the same value"? – Sasha Jan 23 '22 at 20:12
  • @Sasha I did a little research and found that you can't create multiple instances of an enum using new keyword. Which means only one instance of an enum is created. One might then think we can switch on pointers. But sadly you cant do that because pointers are only known at runtime. To emphasize the point, switch statements only work on values known at compile time. To emphasize further, since you only and can only make the pointer const; Java has no way of knowing what value is stored in your enum variable. You can change that value at anytime, during runtime. – user13947194 Jan 23 '22 at 20:45
  • @user13947194… ([0] “you can't create multiple instances of an enum using new keyword” — of course.) So, I've checked the generated bytecode. [1] You were right that, in case of enums, Java's `switch` doesn't simply compare pointers (although I disagree that pointer is always unknown at compile time; it's possible to know in some cases; but Java doesn't use that). [2] You were wrong that it checks the values of the fields; instead, it checks the result of the call to the enum's predefined virtual method; that's the thing a user can't influence (regardless to whether fields are const or no). – Sasha Jan 24 '22 at 10:51
  • @user13947194, so, in general, I oppose to your assumption that inability to mark an object value as const somehow relates to the restriction of using enum aliases as `switch` case labels. – Sasha Jan 24 '22 at 11:03
  • @Sasha You mind telling me how pointers can be known at compile time? Whether it checks a value or a value obtained from a method is not the point. The point is you can change the value of your enum variable at anytime via assigning it a different value. `MyEnum y = MyEnum.a; y = MyEnum.z;` If you further 'oppose' my 'assumption' I can't make a better case. – user13947194 Jan 25 '22 at 01:03
  • @user13947194, "you can change the value of your enum variable at anytime via assigning it a different value". You can't. In `MyEnum y = MyEnum.a; y = MyEnum.z`, exactly the "pointer" gets changed (not the "object" itself). And when `MyEnum y` is marked as `final`, changing the "pointer" is forbidden. (As for the pointers at compile time, it's off-topic, because it's not used here anyway; and I was partially wrong — not the pointers themselves but their offsets to a certain base can be theoretically known at compile time (which should be still enough); but that's not used anyway here.) – Sasha Jan 25 '22 at 08:09
  • @Sasha you make a tough point. I must say I never ever create Java enums and always used static final ints. Yes you can't modify a final enum pointer; essentially making it truly immutable. Now all we need to do is compare the offsets; and we know them at compile time! The only thing I can think of is, are these offsets relative to the entire app? – user13947194 Jan 30 '22 at 14:53
  • @user13947194, sorry for not replying, there was a rush at work. I suppose, these offsets are per module (i.e. per `*.dll`- or `*.so`-file in the native world and per `*.jar` file in JRE world). Because every module may expect that all of its “static” data is put into contiguous area by the “linker” but has no clue about other modules' “static” data. But that would be enough, as all values for a specific enum are always declared in the same module (Java doesn't support extending enums). – Sasha Feb 05 '22 at 15:01
  • Nevertheless, I think this is offtopic, as (1) Java uses virtual method calls (not pointer offsets) when comparing enums in `switch` and (2) as well as the pointer offsets strategy, the current strategy (based on virtual method calls) doesn't in any way prevent from using enum aliases in `switch`es. So, to be short, the only thing that prevents us from using enum aliases in `switch`es in Java is the syntax (technical reasons don't prevent it). Do you agree now with me that such syntax is a design flaw? – Sasha Feb 05 '22 at 15:08
  • I am happy that you are busy at work. I am busy coding too, but self study. Now your first logic/ point is that since the entire enum is stored in one JAR file; Java would be able to deduce via offset. There is a problem sadly. A Java object can exist in multiple class/JAR files. Infact a java object can be received over a network. The short story, you can't rely on offsets to deduce a Java Object. Other possible problem is the assumption that Java can manipulate offsets to deduce an object. Once an object is loaded into memory it is now an OS specific environment. – user13947194 Feb 06 '22 at 20:17
  • Your second logic is that your logic one is off topic aka irrelevant to our discussion; as Java uses virtual method calls to get enum value. This shows me you didn't learn from my previous elaborations. You cannot switch on method calls as methods calls are not integer values. You cannot switch on pointers because pointers are only known at runtime. – user13947194 Feb 06 '22 at 20:24
  • @user13947194, yes, let's really stop discussion of pointers, because they are really offtopic (despite I believe that you're not 100% correct about them). Method calls aren't integer values but they return integer values. To be precise, Java uses virtual method call to determine the integer value associated with the result of an enum-typed expression in parentheses (after `switch`) while the integer values associated with the enum values used as `case` labels are known at compile-time. (That's how it works de-facto, you can check that with `javap`.) – Sasha Feb 08 '22 at 07:47
  • (BTW, I need to say sorry, because some time ago I said “I never stated that enums have associated ints”, but now I do state that. Because at that point of time I didn't care about actual implementation and didn't look into `javap` and then I did.) And, to say truth, now I don't understand your point at all: IIUC, you're saying that `switch` for enums in Java can be implemented neither by comparing pointers (or offsets) nor by calling a virtual method; but the fact is that `switch` for enums is impemented in Java in some way; does that mean that you assume some _third_ way? – Sasha Feb 08 '22 at 07:47
  • I am happy you finally get that you can't switch on a method; you must switch on the integer it returns. Question: what do you know about polymorphic/ virtual methods. If nothing else you must know that virtual methods are runtime features. Cannot be deduced at compile time. So even if Java doesn't use virtual pointer tables to implement virtual methods; it makes no difference as they are still runtime information. And switch statements require that they be known at compile time. – user13947194 Feb 08 '22 at 12:46
6

this should do:

//Main Class
public class SomeClass {

    //Sub-Class
    public static class AnotherClass {
        public enum MyEnum {
            VALUE_A, VALUE_B
        }    
        public MyEnum myEnum;
    }

    public void someMethod() { 
        AnotherClass.MyEnum enumExample = AnotherClass.MyEnum.VALUE_A; //...

        switch (enumExample) {
            case VALUE_A: { //<-- error on this line
            //..
            break;
            }
        }
    }
}
Woyzeck
  • 115
  • 1
  • 11
6

From Java 14 onwards, one can use switch expressions.

For this post

public enum MyEnum {
    VALUE_A, VALUE_B;
}
public void someMethod() { 
    MyEnum enumExample //...

    switch (enumExample) {
        case VALUE_A -> {
            // logic
        }
        case VALUE_B -> {
            // logic
        }   
    }
}

Switch expression

Like all expressions, switch expressions evaluate to a single value and can be used in statements. They may contain "case L ->" labels that eliminate the need for break statements to prevent fall through. You can use a yield statement to specify the value of a switch expression.

public enum Month {
    JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC;
}

Example 1: Returns value.

public static int getNoOfDaysInAMonth(Month month, boolean isLeapYear) {
    return switch(month) {
        case APR, JUN, SEP, NOV -> 30;
        case FEB -> (isLeapYear)? 29: 28;
        case JAN, MAR, MAY, JUL, AUG, OCT, DEC -> 31;
    };
}

Example 2: Doesn't returns value.

public static void printNoOfDaysInAMonth(Month month, boolean isLeapYear) {
    switch(month) {
        case APR, JUN, SEP, NOV -> {
            System.out.println("30 days");
        }
        case FEB -> {
            System.out.println(((isLeapYear)? 29: 28) + " days");
        }
        case JAN, MAR, MAY, JUL, AUG, OCT, DEC -> {
            System.out.println("31 days");
        }
    };
}

Reference

Switch Expressions

hbamithkumara
  • 2,344
  • 1
  • 17
  • 17
2

This is how I am using it. And it is working fantastically -

public enum Button {
        REPORT_ISSUES(0),
        CANCEL_ORDER(1),
        RETURN_ORDER(2);

        private int value;

        Button(int value) {
            this.value = value;
        }

        public int getValue() {
            return value;
        }
    }

And the switch-case as shown below

@Override
public void onClick(MyOrderDetailDelgate.Button button, int position) {
    switch (button) {
        case REPORT_ISSUES: {
            break;
        }
        case CANCEL_ORDER: {
            break;
        }
        case RETURN_ORDER: {
            break;
        }
    }
}
Jimit Patel
  • 4,265
  • 2
  • 34
  • 58
1

You dont need put instance of enum class, you have to put only enum constant of enum class, like this:

switch (enumExample) {
   case VALUE_A: { <-- puting only constant, it will works.
       //..
      break;
   }
0

Write someMethod() in this way:

public void someMethod() {

    SomeClass.AnotherClass.MyEnum enumExample = SomeClass.AnotherClass.MyEnum.VALUE_A;

    switch (enumExample) {
    case VALUE_A:
        break;
    }

}

In switch statement you must use the constant name only.

dash1e
  • 7,677
  • 1
  • 30
  • 35