1

Is there a way to define a constant Map for the use in a switch statement? All my trials with static Maps from here, here and others were not successful. Why isn't the Map constant?

For the line case (kws.get(KEYWORD_NAME)): I always get constant string expression required error.

public class Demo {

  public static final String KEYWORD_NAME = "Name";
  public static final String KEYWORD_TYPE = "Type";

  private static final Map<String, String> kws = Collections.unmodifiableMap(
  new HashMap<String, String>() {{
    put(KEYWORD_NAME, KEYWORD_NAME.toLowerCase());
    put(KEYWORD_TYPE, KEYWORD_TYPE.toLowerCase());
  }});

  public static void parse(String kw){
    switch(kw){
      case (kws.get(KEYWORD_NAME)):
        System.out.println("Test");
        break;
    default:
      System.out.println("Unknown");
    }
  }
}
Community
  • 1
  • 1
raedma
  • 293
  • 1
  • 12
  • 3
    `case` expressions must be *compile-time constants*. How do you expect the compiler to know what `kws.get(KEYWORD_NAME)` will do? – Jon Skeet Nov 05 '15 at 16:45
  • 1
    Every `switch` statement can be accomplished with a Map. You could, for example, create a `Map`. Java 8 method references make this fairly easy. – VGR Nov 05 '15 at 16:49

2 Answers2

7

No, because the case labels in a switch statement must be either constant expressions or enumerators.

The reference to your Map is final, and your map is unmodifiable. But the latter is enforced at run time. The compiler does not treat the object as a constant.

From the Java Language Specification, 14.11: The switch statement:

SwitchLabel:
case ConstantExpression : 
case EnumConstantName : 
default :

Constant expressions can be composed only of primitive and String literals, certain operators without side-effects, constant variables, and a few other components that can be computed at compile-time. (A constant variable is a final variable of primitive or String type that's been initialized to a constant expression.) More detail is at 15.28: Constant expressions.

Andy Thomas
  • 84,978
  • 11
  • 107
  • 151
0

I do not know your use case, but instead of using unmodifiable map you can use parametrized enum:

>> when:

public enum Demo {
     NAME("Name"),
     TYPE("Type"),
     NOT_SUPPORTED("");

    private String code;
    private static final Map<String, Demo> CODE_VALUE_MAP = new LinkedHashMap<>();

    // -- static
    static {
        for (Demo demo : Demo.values()) {
            CODE_VALUE_MAP.put(demo.getCode(), demo );
        }
     }

   public static Demo forCode(@NotNull String code) {
        if (code!= null) {
            return CODE_VALUE_MAP.getOrDefault(code.toUpperCase(), NOT_SUPPORTED);
           }
           return NOT_SUPPORTED;
       }    
   }

   // -- constructor
   Demo(String code) {
       this.code= code;
   }

   // -- public methods
   public String getCode() {
       return code;
   }
}

>>Then:

...
public static void parse(String kw){
 Demo demo = Demo.forCode(kw);
 switch(demo){
  case NAME:
    System.out.println("Test");
    break;
default:
  System.out.println("Unknown");
}
...
Petr Hunka
  • 312
  • 5
  • 11