Constant expressions from an Enum

Luis Sep picture Luis Sep · May 8, 2013 · Viewed 12.6k times · Source

Is there any way of converting an enum into a constant expression? I want my switch operator to choose among the values of an enum, but I got a compile error "case expressions must be constant expressions", so I tried to declare it in a variable:

final int REG = MyEnum.REG.getIndex().intValue();

switch (service.getIndex()) {

case REG:

But I still get the same error. According to Oracle's documentation http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.28

A compile-time constant expression is an expression denoting a value of primitive type or a String that does not complete abruptly and is composed using only the following:

•Literals of primitive type and literals of type String

So it isn't working because I'm not using a literal. I think I will have to declare it as:

final int REG = 8;

But it'd be much better to link it to the enum. Is there any way of doing this?

EDIT

Turns out I don't need to use any final variable. It is just as simple as:

switch (service) {

case REG:

It didn't occur to me till I saw Andrea's comment. Thanks for your answers.

Answer

Andreas Fester picture Andreas Fester · May 8, 2013

If possible, modify your getIndex() method so that it returns an enum instead of an integer. If this is not possible, you need to map the index to an enum element:

Given the following enum:

public enum Index {
   ONE,
   TWO,
   THREE
}

you can map your index to an enum element by using

Index.values()[index]

Given your method Integer getIndex(), you can then do something like

switch(Index.values()[getIndex()])
    case ONE : ... 
       break;

    case TWO : ...
       break;

    case THREE : ...
       break;
}

Note that this might throw an ArrayIndexOutOfBoundsException if you try to access an index within the enum which is larger than the number of enum elements (e.g. in the sample above, if getIndex() returns a value > 2).


I would encapsulate the expression Index.values()[getIndex()] into an enum method like valueOf(int index), similar to the default valueOf(String s). You can then also handle the valid array index check there (and for example return a special enum value if the index is out of range). Similarly, you can then also convert discrete values which have special meanings:

public enum Index {
   ZERO,
   ONE,
   TWO,
   THREE,
   REG,
   INVALID;


   public static Index valueOf(int index) {

       if (index == 8) {
          return REG;
       }

       if (index >= values().length) {
          return INVALID;
       }

       return values()[index];
   }
}

This is an example only - in any case, it generally depends on the range of values you get from your getIndex() method, and how you want to map them to the enum elements.

You can then use it like

switch(Index.valueOf(service.getIndex())) {
   case ZERO : ... break;
   ...
   case REG : ... break;
   ...
}

See also Cast Int to enum in Java for some additional information (especially the hint that values() is an expensive operation since it needs to return a copy of the array each time it is called).