在java enum中自动分配值

时间:2013-06-08 11:59:39

标签: java enums

我有一个有趣的要求,我们有大型的形式

的枚举
public enum BpcCmsError {

    ERROR_TYPE_1("Error message 1"), 
    ERROR_TYPE_2("Error message 2"),
    ERROR_TYPE_3("Error message 3");


    private int errorCode;
    private final String errorMessage;
    public static final int ERRORCODE_BASE = 100;

我需要分配一些唯一的错误代码,从数字开始并向上计数,所以我有一个构造函数:

private BpcCmsError(String message) {
        this.errorMessage = message;
 }

和静态块

static {
        int code = ERRORCODE_BASE;
        for (BpcCmsError error : EnumSet.allOf(BpcCmsError.class)) {
            error.errorCode = ++code;
       }
}

效果很好。

但是,我需要一些额外的灵活性来分配这些错误代码,理想情况如下:

    ERROR_TYPE_1("Error message 1"), 
    ERROR_TYPE_2("Error message 2"),
    ERROR_TYPE_3(200,"Error message for code");

意图是2-args构造函数会导致后续错误代码从第一个参数的值开始。在我的情况下,错误代码将是100,101,200,201等。当然,我需要检查是否应该允许此跳转,例如,我们可能已经计算过200。有关如何使用Java中的枚举实现此目的的任何提示?

3 个答案:

答案 0 :(得分:4)

这不像你需要一个枚举......你似乎试图映射一系列整数错误代码以防止错误消息。

在这种情况下,您需要某种Map

所以你有一些东西(没有IDE因为愚蠢的语法错误而道歉)

public class BpcCmsError {
    private Map<int, String> errorMap = new HashMap<int, String>();
    private int lastErrorCode = 0;

    public void addError(String message) {
       errorMap.put(lastErrorCode++, message);
    }

     public void addError(int code, String message) {
       errorMap.put(code, message);
       lastErrorCode = code++;
    }

    public String getMessage(int code) {
       return errorMap.get(code);
    }

}

答案 1 :(得分:2)

显而易见的答案是拥有一个private static int nextErrorCode并在每次使用时增加它......但这不起作用,因为你不能从枚举构造函数中引用静态字段(它被称为部分枚举的静态初始化)。来自Java 7 spec

  

从构造函数,实例初始化程序块或该类型的实例变量初始化程序表达式引用不是常量变量(第4.12.4节)的枚举类型的static字段是编译时错误

解决方法是将计数器保留在一个简单的静态内部类中:

public enum BpcCmsError {

  ERROR_TYPE_1("Error message 1"),
  ERROR_TYPE_2("Error message 2"),
  ERROR_TYPE_3(200, "Error message 3");

  private final int errorCode;
  private final String errorMessage;

  private BpcCmsError(String message) {
    this.errorMessage = message;
    this.errorCode = NextErrorCode.get();
  }

  private BpcCmsError(int errorCode, String message) {
    this.errorMessage = message;
    this.errorCode = NextErrorCode.get(errorCode);
  }

  private static class NextErrorCode {
    private static int nextErrorCode = 100;

    public static int get() {
      return nextErrorCode++;
    }

    public static int get(int errorCode) {
      if (errorCode < nextErrorCode) {
        throw new IllegalArgumentException("Requested error code " + errorCode + " exceeds next valid error code " + nextErrorCode);
      }
      nextErrorCode = errorCode;
      return nextErrorCode++;
    }
  }
}

答案 2 :(得分:1)

我建议您在EnumMap块中构建的enum中保留static个错误代码。

public enum ErrorCode {

    ERROR_TYPE_1("Error message 1"),
    ERROR_TYPE_2("Error message 2"),
    ERROR_TYPE_3(200, "Error message 3"),
    ERROR_TYPE_4("Error message 1"),
    ERROR_TYPE_5(300, "Error message 2"),
    ERROR_TYPE_6("Error message 3");
    private final int errorCode;
    private final String errorMessage;
    private static final Map<ErrorCode, Integer> ERROR_CODES;
    private static final int ERROR_CODE_BASE = 100;

    static {
        ERROR_CODES = new EnumMap<>(ErrorCode.class);
        int code = ERROR_CODE_BASE;
        for (final ErrorCode ec : values()) {
            if (ec.errorCode > 0) {
                if (ec.errorCode <= code) {
                    throw new ExceptionInInitializerError("Non unique code for " + ec);
                }
                code = ec.errorCode;
            }
            ERROR_CODES.put(ec, code++);            
        }
    }

    private ErrorCode(final String errorMessage) {
        this(-1, errorMessage);
    }

    private ErrorCode(final int errorCode, final String errorMessage) {
        this.errorCode = errorCode;
        this.errorMessage = errorMessage;
    }

    public String getErrorMessage() {
        return errorMessage;
    }

    public int getErrorCode() {
        return ERROR_CODES.get(this);
    }
}

这非常灵活 - 您可以非常轻松地更改代码生成的逻辑。

java EnumMap也非常漂亮,它是针对Map个密钥优化的enum

快速测试:

public static void main(String[] args) throws Exception {
    for(final ErrorCode errorCode : ErrorCode.values()) {
        System.out.println(errorCode + ", code is " + errorCode.getErrorCode());
    }
}

输出:

ERROR_TYPE_1, code is 100
ERROR_TYPE_2, code is 101
ERROR_TYPE_3, code is 200
ERROR_TYPE_4, code is 201
ERROR_TYPE_5, code is 300
ERROR_TYPE_6, code is 301