Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

switch over value of enum: case expressions must be constant expressions

I have an enum with the following structure:

public enum Friends {
    Peter("Peter von Reus", "Engineer"),
    Ian("Ian de Villiers", "Developer"),
    Sarah("Sarah Roos", "Sandwich-maker");

    private String fullName;
    private String occupation;

    private Person(String fullName, String occupation) {
        this.fullName = fullName;
        this.occupation = occupation;
    }

    public String getFullName() {
        return this.fullName;
    }

    public String getOccupation() {
        return this.occupation;
    }
}

I would now like to use switch to determine, if a variable name is associated with a certain enum:

//Get a value from some magical input
String name = ...

switch (name) {
    case Friends.Peter.getFullName():
        //Do some more magical stuff
        ...
    break;
    case Friends.Ian.getFullName():
        //Do some more magical stuff
        ...
    break;
    case Friends.Sarah.getFullName():
        //Do some more magical stuff
        ...
    break;
}

This seems perfectly legal to me, but I'm getting the error case expressions must be constant expressions in Eclipse. I can get around this with a simple set of if statements but I would like to know the reason for this error and how things might go south if this was allowed.

NOTE: I cannot change the structure of Friends

like image 825
Ian2thedv Avatar asked Aug 07 '14 13:08

Ian2thedv


People also ask

Can you use a switch statement around an enum?

We can use also use Enum keyword with Switch statement. We can use Enum in Switch case statement in Java like int primitive.

What is constant expression in Java?

Constant Expressions Expressions like these are called constant expressions, as the compiler will calculate them and produce a single compile-time constant. As defined in the Java language specification, the following operators and expressions may be used for constant expressions: Unary operators: +, -, ~, !


2 Answers

If I understand your question, you can use valueOf(String) like

String name = "Peter";
Friends f = Friends.valueOf(name);
switch (f) {
case Peter:
    System.out.println("Peter");
    break;
case Ian:
    System.out.println("Ian");
    break;
case Sarah:
    System.out.println("Sarah");
    break;
default:
    System.out.println("None of the above");
}

Also, this

private Person(String fullName, String occupation) {
    this.fullName = fullName;
    this.occupation = occupation;
}

Should be

private Friends(String fullName, String occupation) {
    this.fullName = fullName;
    this.occupation = occupation;
}

Because Person != Friends.

Edit

Based on your comment, you will need to write a static method to get the correct Friends instance,

    public static Friends fromName(String name) {
        for (Friends f : values()) {
            if (f.getFullName().equalsIgnoreCase(name)) {
                return f;
            }
        }
        return null;
    }

Then you can call it with,

    String name = "Peter von Reus";
    Friends f = Friends.fromName(name);

valueOf(String) will match the name of the enum field. So "Ian", "Sarah" or "Peter".

like image 126
Elliott Frisch Avatar answered Oct 30 '22 14:10

Elliott Frisch


This seems perfectly legal to me

Well it's not - a method call is never a constant expression. See JLS 15.28 for what constitutes a constant expression. And a case value always has to be a constant expression.

The simplest fix would be to have a Friend.fromFullName static method, which perhaps looked the Friend up in a HashMap<String, Friend>. (You don't have to have that method in Friend of course... it's just that would be the most conventional place.) Then you could switch over the enum rather than the name.

As a side note, your enum name should be in the singular and with ALL_CAPS members, so Friend.PETER etc.

like image 13
Jon Skeet Avatar answered Oct 30 '22 14:10

Jon Skeet