Какой лучший способ реализовать `next` и` previous` в типе перечисления?
Предположим, что у меня есть перечисление:
enum E {
A, B, C;
}
Как показано в этом ответе lucasmo, значения перечисления хранятся в статическом массиве в порядок их инициализации, и вы можете позже получить (клон) этого массива с помощью E.values()
.
Теперь предположим, что я хочу реализовать E#getNext
и E#getPrevious
так, чтобы все следующие выражения оценивались как true
:
E.A.getNext() == E.B
E.B.getNext() == E.C
E.C.getNext() == E.A
E.A.getPrevious() == E.C
E.B.getPrevious() == E.A
E.C.getPrevious() == E.B
Моей текущей реализацией для getNext
является следующее:
public E getNext() {
E[] e = E.values();
int i = 0;
for (; e[i] != this; i++)
;
i++;
i %= e.length;
return e[i];
}
и аналогичный метод для getPrevious
.
Однако этот код кажется в лучшем случае громоздким (например, "пустым" циклом for
, допустимым злоупотреблением переменной счетчика и потенциально ошибочным в худшем случае (мысленное отражение, возможно).
Каким будет лучший способ реализовать методы getNext
и getPrevious
для типов перечислений в Java 7?
ПРИМЕЧАНИЕ: Я не намерен задавать этот вопрос субъективным. Моя просьба о "наилучшей" реализации - это сокращение, требующее, чтобы реализация была самой быстрой, чистой и удобной для обслуживания.
Ответы
Ответ 1
Попробуйте следующее:
public static enum A {
X, Y, Z;
private static A[] vals = values();
public A next()
{
return vals[(this.ordinal()+1) % vals.length];
}
Реализация previous()
остается как упражнение, но напомним, что в Java, modulo a % b
может возвращать отрицательное число.
EDIT: как было предложено, сделайте приватную статическую копию массива values()
, чтобы избежать копирования массива каждый раз, когда вызывается next()
или previous()
.
Ответ 2
В качестве альтернативы можно как-то идти по строкам следующей идеи:
public enum SomeEnum {
A, B, C;
public Optional<SomeEnum> next() {
switch (this) {
case A: return Optional.of(B);
case B: return Optional.of(C);
// any other case can NOT be mapped!
default: return Optional.empty();
}
}
Примечания:
- В отличие от другого ответа, этот способ показывает некоторое неявное отображение; вместо того, чтобы полагаться на
ordinal()
. Конечно, это означает больше кода; но это также заставляет автора считать, что значит добавлять новые константы или удалять существующие. Если полагаться на порядковый номер, ваше предположение неявное заключается в том, что порядок основан на порядке, используемом для объявления константы enum. Поэтому, когда кто-то возвращается через 6 месяцев и должен добавить новую константу, он должен понимать, что для новой константы Y требуется X, Y, Z
... вместо просто добавления X, Z, Y
!
- Бывают ситуации, когда для "последней" константы перечисления нет смысла иметь "первый" как преемник. Подумайте о размерах футболок для примеров. XXL.next() - это точно не XS. Для таких ситуаций более подходящим ответом является использование опции "Дополнительно".