2013-06-08 3 views
1

У меня есть интересное требование, мы имеем больших перечисления видаАвтоматически присваивать значения в Java перечислении

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-арг конструктор будет вызывать последующие коды ошибок, чтобы начать от значения, что первым параметр. В моем случае коды ошибок будут 100, 101, 200, 201 и т. Д. Конечно, мне нужно проверить, что этот прыжок должен быть разрешен, например, мы, возможно, уже насчитывали прошлое 200. Любые советы о том, как добиться этого, используя enums в Java?

+1

Создать статический INT 'nextCode' и либо принять следующий код из него и увеличить его или использовать код из конструктора (после проверки достоверности) и установите 'nextCode' в заданный код + 1 –

+0

Вы не можете ссылаться на статические поля из конструкторов enum:' error: незаконная ссылка на статическое поле из инициализатора'. – Thomas

+0

@Thomas Я вижу, спасибо, но есть взломать: создайте статический класс внутри enum и поместите статический int внутри этого класса. –

ответ

1

Я хотел бы предложить вам сохранить EnumMap кодов ошибок в вашем enum, что вы строите в a 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 
+0

коды должны быть уникальными, я предполагаю, что этот подход может быть изменен для поддержки этого? –

+1

@ Jan-OlavEide Я изменил код, чтобы учесть это. 'Enum' теперь будет вызывать' ExceptionInInitializerError', если код не является unqiue. –

4

Это не похоже, что вам нужен Enum ... вы пытаетесь сделать карту последовательность целых кодов ошибок от сообщений об ошибках.

В этом случае вы хотите какой-то 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); 
    } 

} 
+0

Я не буду ниспровергать, потому что альтернативные подходы могут быть полезны, но это звучит для меня как OP _does_ want enum. Это небезопасно и нечитаемо для возврата произвольных значений 'int' из некоторого API. И как только у вас есть перечисление, наличие его собственного сообщения об ошибке довольно элегантно. – Thomas

+0

Это должно быть перечисление из-за совместимости с существующим кодом, поэтому я не могу использовать карту в этом случае. –

2

Очевидным ответом было бы имеют private static int nextErrorCode и увеличивайте его каждый раз, когда вы используете один ... но это не работает, потому что вы не можете ссылаться на статическое поле из конструктора enum (который называется частью статической инициализации перечисления). Из Java 7 spec:

It is a compile-time error to reference a static field of an enum type that is not a constant variable (§4.12.4) from constructors, instance initializer blocks, or instance variable initializer expressions of that type.

Чтобы обойти эту проблему, чтобы сохранить счетчик в простом статическом внутреннем классе вместо:

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++; 
    } 
    } 
} 
Смежные вопросы