I saw it suggested on a blog that the following was a reasonable way to do a \"reverse-lookup\" using the getCode(int)
in a Java enum:
public en
Both ways are perfectly valid. And they have technically the same Big-Oh running time.
However, if you save all of the values to a Map first, you save the time it takes to iterate through the set each time you want to do a lookup. So, I think that the static map and initializer are a slightly better way to go.
Maps.uniqueIndex from Google's Guava is quite handy for building lookup maps.
Update: Here is an example using Maps.uniqueIndex
with Java 8:
public enum MyEnum {
A(0), B(1), C(2);
private static final Map<Integer, MyEnum> LOOKUP = Maps.uniqueIndex(
Arrays.asList(MyEnum.values()),
MyEnum::getStatus
);
private final int status;
MyEnum(int status) {
this.status = status;
}
public int getStatus() {
return status;
}
@Nullable
public static MyEnum fromStatus(int status) {
return LOOKUP.get(status);
}
}
Though it has higher overhead, the static map is nice because it offers constant-time lookup by code
. Your implementation's lookup time increases linearly with the number of elements in the enum. For small enums, this simply will not contribute significantly.
One issue with both implementations (and, arguably, with Java enums in general) is that there's really a hidden extra value that a Status
can take on: null
. Depending on the rules of the business logic, it may make sense to return an actual enum value, or throw an Exception
, when the lookup "fails."
Obviously the map will provide constant time lookup whereas the loop won't. In a typical enum with few values, I don't see a problem with the traversal lookup.
In Java 8 I would just add the following factory method to your enum and skip the lookup Map.
public static Optional<Status> of(int value) {
return Arrays.stream(values()).filter(v -> value == v.getCode()).findFirst();
}
Here is an alternative which may be even a bit faster:
public enum Status {
WAITING(0),
READY(1),
SKIPPED(-1),
COMPLETED(5);
private int code;
private Status(int code) {
this.code = code;
}
public int getCode() { return code; }
public static Status get(int code) {
switch(code) {
case 0: return WAITING;
case 1: return READY;
case -1: return SKIPPED;
case 5: return COMPLETED;
}
return null;
}
}
Of course, this is not really maintainable if you want to be able to add more constants later.