在Java中为枚举引入默认值的通用机制

在Java中为枚举引入默认值的通用机制,java,Java,在我们当前的项目中,我们正在将一些神奇的数字从数据库映射到java枚举,如下所示: public interface WithCode { Integer getCode(); } public enum Role implements WithCode { OWNER(1), ADMIN(2), USER(3); @Getter Integer code; Role(Integer code) { this.code =

在我们当前的项目中,我们正在将一些神奇的数字从数据库映射到java枚举,如下所示:

public interface WithCode {
    Integer getCode();
}


public enum Role implements WithCode {
    OWNER(1),
    ADMIN(2),
    USER(3);

    @Getter Integer code;

    Role(Integer code) {
        this.code = code;
    }
}
我们有很多这样的方法,所以我们创建了一个实用程序,可以通过ID查找适当的枚举,如下所示:

public interface EnumLookuper {
    static <T extends Enum<T> & WithCode> T ofCode(int code, Class<T> enumType) {
        return Arrays.stream(enumType.getEnumConstants())
                .filter(value -> Objects.equals(value.getCode(), code))
                .findFirst()
                .orElseThrow(() -> new IllegalArgumentException(String.format("Unknown %s with code %d", enumType.getName(), code)));
    }
}
用接口强制默认值实际上是行不通的,因为我们需要为每个枚举成员提供默认值。有没有为每个枚举引入优雅的回退/未知值的想法

编辑 使用自定义“未知值接口”将迫使我对每个枚举成员实现未知值,例如:

interface UnknownValueProvider<T> {
  T unknown();
}

public enum Role implements WithCode, UnknownValueProvider<Role> {
    OWNER(1) {
    public Role unknown() {
        return ...;
    }
}
接口未知值提供程序{
T未知();
}
公共枚举角色使用代码实现,未知值提供程序{
业主(1){
公共角色未知(){
返回。。。;
}
}
(注意:我不熟悉您拥有的部分代码,即按ID获取枚举的第二个代码块的大部分。它似乎过于复杂/不直观,并且与我发现的执行类似功能的所有代码都不同,请参见。有什么原因使它像我丢失的那样?)


我以前遇到过类似的问题,但有一些细微的区别。在我的例子中,我使用
valueOf()
获取枚举,但我想使其不区分大小写。因此,在我的枚举中,我重载了(?)
valueOf(anyCaseParam)
以返回
valueOf(anyCaseParam.toUpperCase())

我的建议 您应该将
UNKNOWN(-1)
添加到枚举列表中(这样您就有了一个要检索的枚举)

根据这个答案,我修改了最后一段代码,以符合您的要求:

public T getByID(int num) {

    // Old code: 
       //return map.get(num);


    int unknownEnum= -1;

    if(map.get(num)!=null)
      return map.get(num);
    else
      return map.get(unknownEnum);
}

如果您愿意,您甚至可以使用另一个抛出异常的方法,而不是返回
未知的
值。

您无法返回一些新的枚举值,除非您直接将其添加到枚举类中。可能返回null/Optional会有帮助我正在考虑使用
Optional
,但我需要更改很多客户机代码在这种情况下,我看到的最佳解决方案是将此未知字段添加到每个枚举中(在过去可以预期它们的需要)。尝试破解enum是不值得的。抱歉,我可能还不够清楚。我指的是你从向前获取实例的角度所做的事情。如果你真的需要使用enum实例,或者你可以用一个公共接口替换它,比如说
命令
。你的enum将使用code&Co同时实现
mmand
并且您还有一个实现该接口的
UnknownCommand
类。然后,您的lookuper将返回一个
命令
,如果可以找到匹配项,它将是一个枚举实例,或者是一个未知实例,您的代码只需调用
命令。execute()
public T getByID(int num) {

    // Old code: 
       //return map.get(num);


    int unknownEnum= -1;

    if(map.get(num)!=null)
      return map.get(num);
    else
      return map.get(unknownEnum);
}