Reputation: 345
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.
Upvotes: 5
Views: 1396
Reputation: 17319
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).
Upvotes: 5
Reputation: 328775
I would personally keep it simple (YAGNI) and use the ordinal value but:
enum code:
public enum Action {
START(0),
QUIT(1);
private final int code;
Action(int code) {
this.code = code;
}
public int getCode() {
return code;
}
public static Action of(int code) {
try {
return Action.values()[code];
} catch (IndexOutOfBoundsException e) {
throw new IllegalArgumentException("not a valid code: " + code);
}
}
}
test
@Test
public testActionEnumOrder() {
int i = 0;
for (Action a : Action.values()) {
assertEquals(a.getCode(), i++);
}
}
If you change QUIT(1)
to QUIT(2)
for example, the test will fail. When that happens, you can use a HashMap or a lookup loop.
Upvotes: 0
Reputation: 122414
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;
}
}
Upvotes: 1