Java枚举反向查找最佳实践
我在博客上看到建议以下内容是在 Java 枚举中使用 getCode(int)
进行“反向查找”的合理方法:
public enum Status {
WAITING(0),
READY(1),
SKIPPED(-1),
COMPLETED(5);
private static final Map<Integer,Status> lookup
= new HashMap<Integer,Status>();
static {
for(Status s : EnumSet.allOf(Status.class))
lookup.put(s.getCode(), s);
}
private int code;
private Status(int code) {
this.code = code;
}
public int getCode() { return code; }
public static Status get(int code) {
return lookup.get(code);
}
}
对我来说,静态映射和静态初始化器看起来都是一个坏主意,而我的第一个想法想法是这样编写查找代码:
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) {
for(Status s : values()) {
if(s.code == code) return s;
}
return null;
}
}
这两种方法都存在明显的问题吗?是否有推荐的方法来实现这种查找?
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 enum Status {
WAITING(0),
READY(1),
SKIPPED(-1),
COMPLETED(5);
private static final Map<Integer,Status> lookup
= new HashMap<Integer,Status>();
static {
for(Status s : EnumSet.allOf(Status.class))
lookup.put(s.getCode(), s);
}
private int code;
private Status(int code) {
this.code = code;
}
public int getCode() { return code; }
public static Status get(int code) {
return lookup.get(code);
}
}
To me, the static map and the static initializer both look like a bad idea, and my first thought would be to code the lookup as so:
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) {
for(Status s : values()) {
if(s.code == code) return s;
}
return null;
}
}
Are there any obvious problems with either method, and is there a recommended way to implement this kind of lookup?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
Maps.uniqueIndex 来自 Google 的 Guava 对于构建查找地图非常方便。
更新:以下是在 Java 8 中使用
Maps.uniqueIndex
的示例:Maps.uniqueIndex from Google's Guava is quite handy for building lookup maps.
Update: Here is an example using
Maps.uniqueIndex
with Java 8:虽然静态映射的开销较高,但它还是不错的,因为它通过
code
提供恒定时间查找。您的实现的查找时间随着枚举中元素的数量线性增加。对于小型枚举,这根本不会有太大贡献。这两种实现(也可以说是一般的 Java 枚举)的一个问题是
Status
确实可以采用一个隐藏的额外值:null
。根据业务逻辑的规则,当查找“失败”时,返回实际的枚举值或抛出Exception
可能是有意义的。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 anException
, when the lookup "fails."这是一个可能更快一点的替代方案:
当然,如果您希望以后能够添加更多常量,那么这并不是真正可维护的。
Here is an alternative which may be even a bit faster:
Of course, this is not really maintainable if you want to be able to add more constants later.
显然,映射将提供恒定时间查找,而循环则不会。在具有很少值的典型枚举中,我没有发现遍历查找有问题。
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.
这是 Java 8 的替代方案(带有单元测试):
Here is an Java 8 alternative (with unit test):
在 Java 8 中,我只需将以下工厂方法添加到枚举中并跳过查找映射。
In Java 8 I would just add the following factory method to your enum and skip the lookup Map.
两种方式都是完全有效的。从技术上讲,它们的运行时间是相同的。
但是,如果您首先将所有值保存到 Map,则可以节省每次要进行查找时迭代该集合所需的时间。所以,我认为静态映射和初始化程序是一个稍微更好的方法。
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.