Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create a enum factory method out of a unique instance value

I have created an Enum to define certain actions. Programming against a external API I am forced to use an Integer to express this action. That's why I have added an integer instance field to my Enum. This should be d'accord with Joshua Bloch's Effective Java, instead of relying on ordinal() or the order of the Enum constants using values()[index].

public enum Action {

    START(0),

    QUIT(1);

    public final int code;

    Protocol(int code) {
         this.code = code;
     }
}

I get an integer value what from the API and now I want to create an Enum value out of it, how can I implement this in the most generic fashion?

Obviously, adding such a factory method, will not work. You cannot instantiate an Enum.

Action valueOf(int what) {
     return new Action(what);
}

Of course, I can always make a switch-case statement and add all the possible codes and return the appropriate constant. But I want to avoid defining them in two places at the same time.

like image 483
Max Rhan Avatar asked Jan 18 '13 18:01

Max Rhan


People also ask

Can we inherit enum in Java?

As we have learned, we cannot inherit enum classes in Java. However, enum classes can implement interfaces.

Which method is used in Java to get the values of an enum?

The Java compiler internally adds the valueOf() method when it creates an enum. The valueOf() method returns the value of given constant enum.

Can enum hold values?

The Enum constructor can accept multiple values. Moreover, we can add computed values to our enum by adding methods to perform operations.

Are enums implicitly static and final?

An enum declaration is implicitly final unless it contains at least one enum constant that has a class body. A nested enum type is implicitly static. It is permitted for the declaration of a nested enum type to redundantly specify the static modifier.


2 Answers

If you're going to have a lot of them, you can use a HashMap<Integer, Action>:

private static final Map<Integer, Action> actions = new HashMap<>(values().size, 1);

static {
    for (Action action : values())
        actions.put(action.code, action);
}

// ...

public static Action valueOf(int what) {
    return actions.get(what);
}

This is useful if you're going to have a large number of Action values since the HashMap lookup is O(1).

like image 168
Brian Avatar answered Sep 28 '22 22:09

Brian


If you are sure that your codes will always be sequential and starting from 0 then the most efficient option would be

public enum Action {
    START(0),

    QUIT(1);

    public static final Action[] ACTIONS;
    static {
      ACTIONS = new Action[values().length];
      for(Action a : values()) {
        ACTIONS[a.code] = a;
      }
    }

    public final int code;

    Protocol(int code) {
         this.code = code;
     }
}
like image 28
Ian Roberts Avatar answered Sep 28 '22 23:09

Ian Roberts