![]() |
面冷心慈的手套 · 原生 js 中 ...· 11 月前 · |
![]() |
光明磊落的猕猴桃 · 恶意代码分析第七章Lab-07-03实战分析 ...· 2 年前 · |
![]() |
淡定的小刀 · React(三)状态值、样式、双向绑定、渲染 ...· 2 年前 · |
![]() |
强悍的书签 · 在Mac上安装和使用Docker搭建lara ...· 2 年前 · |
我在
suggested on a blog
上看到,在Java enum中使用
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;
}
这两种方法都有明显的问题吗?有没有推荐的方法来实现这种查找?
来自谷歌 Guava 的 Maps.uniqueIndex 在构建查找地图方面非常方便。
更新:以下是在Java8中使用
Maps.uniqueIndex
的示例:
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);
}
尽管静态映射具有较高的开销,但它很好用,因为它提供了按
code
进行的恒定时间查找。您的实现的查找时间随着枚举中元素的数量线性增加。对于小的枚举,这根本不会有太大的贡献。
这两种实现的一个问题是:
null
实际上是
Status
可以承担的一个隐藏的附加值。根据业务逻辑的规则,当查找“失败”时,返回实际的枚举值或抛出
Exception
可能是有意义的。
两种方式都是完全有效的。从技术上讲,它们的运行时间是相同的。
但是,如果您首先将所有值保存到Map中,则可以在每次要执行查找时节省迭代集合所需的时间。因此,我认为静态映射和初始化器是一种更好的方法。
显然,map将提供恒定的时间查找,而循环不会。在一个典型的值很少的枚举中,我看不出遍历查找有什么问题。
这里有一个更快的替代方案:
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;
}
当然,如果您希望以后能够添加更多常量,那么这并不是真正可维护的。
下面是一个Java 8替代方案(使用单元测试):
// DictionarySupport.java :
import org.apache.commons.collections4.Factory;
import org.apache.commons.collections4.map.LazyMap;
import java.util.HashMap;
import java.util.Map;
public interface DictionarySupport<T extends Enum<T>> {
@SuppressWarnings("unchecked")
Map<Class<?>, Map<String, Object>> byCodeMap = LazyMap.lazyMap(new HashMap(), (Factory) HashMap::new);
@SuppressWarnings("unchecked")
Map<Class<?>, Map<Object, String>> byEnumMap = LazyMap.lazyMap(new HashMap(), (Factory) HashMap::new);
default void init(String code) {
byCodeMap.get(this.getClass()).put(code, this);
byEnumMap.get(this.getClass()).put(this, code) ;
static <T extends Enum<T>> T getByCode(Class<T> clazz, String code) {
clazz.getEnumConstants();
return (T) byCodeMap.get(clazz).get(code);
default <T extends Enum<T>> String getCode() {
return byEnumMap.get(this.getClass()).get(this);
// Dictionary 1:
public enum Dictionary1 implements DictionarySupport<Dictionary1> {
VALUE1("code1"),
VALUE2("code2");
private Dictionary1(String code) {
init(code);
// Dictionary 2:
public enum Dictionary2 implements DictionarySupport<Dictionary2> {
VALUE1("code1"),
VALUE2("code2");
private Dictionary2(String code) {
init(code);
// DictionarySupportTest.java:
import org.testng.annotations.Test;
import static org.fest.assertions.api.Assertions.assertThat;
public class DictionarySupportTest {
@Test
public void teetSlownikSupport() {
assertThat(getByCode(Dictionary1.class, "code1")).isEqualTo(Dictionary1.VALUE1);
assertThat(Dictionary1.VALUE1.getCode()).isEqualTo("code1");
assertThat(getByCode(Dictionary1.class, "code2")).isEqualTo(Dictionary1.VALUE2);
assertThat(Dictionary1.VALUE2.getCode()).isEqualTo("code2");
assertThat(getByCode(Dictionary2.class, "code1")).isEqualTo(Dictionary2.VALUE1);
assertThat(Dictionary2.VALUE1.getCode()).isEqualTo("code1");
assertThat(getByCode(Dictionary2.class, "code2")).isEqualTo(Dictionary2.VALUE2);
assertThat(Dictionary2.VALUE2.getCode()).isEqualTo("code2");
}
在Java8中,我只需将以下工厂方法添加到您的枚举中,并跳过查找映射。
public static Optional<Status> of(int value) {
return Arrays.stream(values()).filter(v -> value == v.getCode()).findFirst();
}