Java 枚举反向查找最佳实践

2022-08-31 12:47:25

我在博客上看到有人建议,以下是使用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;
    }
}

这两种方法是否存在任何明显的问题,是否有推荐的方法来实现这种查找?


答案 1

Google的GuavaMaps.uniqueIndex对于构建查找地图非常方便。

更新:下面是一个与 Java 8 一起使用的示例: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);
    }
}

答案 2

尽管它具有较高的开销,但静态映射很不错,因为它提供了 由 的常量时间查找。实现的查找时间随枚举中的元素数线性增加。对于小枚举,这根本不会有重大贡献。code

这两种实现(可以说,一般的Java枚举)的一个问题是,实际上有一个隐藏的额外值可以承担:.根据业务逻辑的规则,当查找“失败”时,返回实际的枚举值或抛出 一个 可能是有意义的。StatusnullException