Я должен пытаться создать обратимое перечисление в Java или являюсь там лучшим путем?

Имейте Вас, рассмотрел использование LockFile:: Простой модуль ? Это уже делает большую часть работы для Вас.

В моем прошлом опыте, я нашел его очень простым в использовании и крепким.

9
задан jaco0646 26 October 2018 в 16:26
поделиться

3 ответа

Это очень распространенный шаблон, и он подходит для перечислений ... но его можно реализовать проще . Нет необходимости в «обратимой карте» - версия, которая принимает номер месяца в конструкторе, лучше подходит для перехода с Month на int . Но пойти другим путем тоже не так уж сложно:

public enum Month {
    JANUARY(1),
    FEBRUARY(2),
    MARCH(3),
    APRIL(4),
    MAY(5),
    JUNE(6),
    JULY(7),
    AUGUST(8),
    SEPTEMBER(9),
    OCTOBER(10),
    NOVEMBER(11),
    DECEMBER(12);

    private static final Map<Integer, Month> numberToMonthMap;

    private final int monthNum;

    static {
        numberToMonthMap = new HashMap<Integer, Month>();
        for (Month month : EnumSet.allOf(Month.class)) {
            numberToMonthMap.put(month.getMonthNum(), month);
        }
    }

    private Month(int monthNum) {
        this.monthNum = monthNum;
    }

    public int getMonthNum() {
        return monthNum;
    }

    public static Month fromMonthNum(int value) {
        Month ret = numberToMonthMap.get(value);
        if (ret == null) {
            throw new IllegalArgumentException(); // Or just return null
        }
        return ret;
    }
}

В конкретном случае чисел, которые, как вы знаете, будут меняться от 1 до N, вы можете просто использовать массив - либо взяв Month.values ​​() [value - 1] , либо кэшируя возвращаемое значение Month.values ​​() для предотвращения создания нового массива при каждом вызове. (И, как говорит Клетус, getMonthNum может просто вернуть ordinal () + 1 .)

Тем не менее, стоит помнить о приведенном выше шаблоне в более общем случае, когда значения могут быть не по порядку или распределены редко.

Важно отметить, что статический инициализатор выполняется после создания всех значений перечисления. Было бы неплохо просто написать

numberToMonthMap.put(monthNum, this);

в конструкторе и добавить инициализатор статической переменной для numberToMonthMap , но это не сработает - вы »

11
ответ дан 4 December 2019 в 11:06
поделиться

Есть более простой способ сделать это. Каждое перечисление имеет метод ordinal () , возвращающий его номер (начиная с нуля).

public enum Month {
  JANUARY,
  FEBRUARY,
  MARCH,
  APRIL,
  MAY,
  JUNE,
  JULY,
  AUGUST,
  SEPTEMBER,
  OCTOBER,
  NOVEMBER,
  DECEMBER;

  public Month previous() {
    int prev = ordinal() - 1;
    if (prev < 0) {
      prev += values().length;
    }
    return values()[prev];
  }

  public Month next() {
    int next = ordinal() + 1;
    if (next >= values().length) {
      next = 0;
    }
    return values()[next];
  }
}

Что касается того, как сохранить это в базе данных, это зависит от того, какую структуру сохранения (если есть) вы используете . JPA / Hibernate имеет возможность отображать значения перечисления по номеру (порядковому номеру) или имени. Месяцы - это то, что вы, вероятно, можете считать неизменным, поэтому просто используйте порядковый номер. Чтобы получить конкретное значение:

Month.values()[ordinalNumber];
4
ответ дан 4 December 2019 в 11:06
поделиться

Вы не должны использовать ordinal () для такого рода вещей, для образца с месяцами он будет работать (потому что он не будет расширенный), но одним из преимуществ перечислений в java является то, что они разработаны таким образом, чтобы их можно было расширять без нарушения работы. Если вы начнете полагаться на ordinal (), все сломается, если вы добавите какое-то значение в середине.

Я бы сделал это, как предлагает Джон Скит (он написал это, когда я писал это), но для случаев, когда представление внутреннего числа находится в четко определенном диапазоне, скажем, от 0 до 20 (или что-то в этом роде), я, вероятно, не буду использовать HashMap и ввести автобокс для int, но лучше использовать обычный массив (например, Month [12]), но оба в порядке (Джон позже изменил свое сообщение, включив это предложение).

Изменить: Для нескольких перечислений, где есть - это естественный порядок (например, отсортированные по месяцам) ordinal (), вероятно, безопасно использовать. Проблемы, с которыми вы рискуете столкнуться, если будете упорствовать, появятся там, где кто-то может изменить порядок перечисления. Как если бы: Для немногих перечислений, где есть естественный порядок (например, отсортированные месяцы), вероятно, безопасно использовать ordinal (). Проблемы, с которыми вы рискуете столкнуться, если будете упорствовать, появятся там, где кто-то может изменить порядок перечисления. Как если бы: Для немногих перечислений, где есть естественный порядок (например, отсортированные месяцы), вероятно, безопасно использовать ordinal (). Проблемы, с которыми вы рискуете столкнуться, если будете упорствовать, появятся там, где кто-то может изменить порядок перечисления. Как если бы: "enum {MALE, FEMALE}" становится "enum {UNKNOWN, FEMALE, MALE}", когда кто-то расширяет программу в будущем, не зная, что вы полагаетесь на порядковый номер.

Давая Джону +1 за то, что он написал то же самое I только что писал.

1
ответ дан 4 December 2019 в 11:06
поделиться
Другие вопросы по тегам:

Похожие вопросы: