Как преобразовать строковый результат перечисления с переопределенным toString () обратно в перечисление?

Учитывая следующее перечисление java:

public enum AgeRange {

   A18TO23 {
        public String toString() {        
            return "18 - 23";
        }
    },
   A24TO29 {
        public String toString() {        
            return "24 - 29";
        }
    },
   A30TO35 {
        public String toString() {        
            return "30 - 35";
        }
    },

}

Есть ли способ преобразовать строковое значение «18–23» в соответствующее значение перечисления, то есть AgeRange.A18TO23?

Спасибо!

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
21
0
22 370
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

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

Это гораздо лучший способ справиться с этим. Затем карта создается, когда есть перечисление, и работает намного быстрее, чем итерация массива.

Spencer Kormos 27.10.2008 18:36

Я тоже рассматриваю этот метод, но в этом перечислении у меня всего около 15 значений. Еще эффективнее создать карту?

Kevin 29.10.2008 05:43

Скорее всего, нет, если честно. Хеш-таблицы отлично подходят для больших объемов данных, но я подозреваю, что сравнение 15 значений (в худшем случае) будет примерно таким же быстрым, как получение хэш-кода, поиск нужного сегмента и т. д.

Jon Skeet 29.10.2008 09:24
for (AgeRange ar: EnumSet.allOf(AgeRange)) {
    if (ar.toString().equals(inString)) {
         myAnswer = ar;
         break;
    }
}

Или что-то вроде того? Просто набрал, не запускал компилятор. Простите (прокомментируйте) опечатки ...

Или используйте подобную логику, чтобы один раз построить карту. Избегайте итераций во время выполнения. Хорошая идея, Джон.

Класс переопределяет «toString ()» - поэтому, чтобы получить обратную операцию, вам нужно переопределить valueOf(), чтобы преобразовать вывод toString() обратно в значения Enum.

public enum AgeRange {

   A18TO23 {
        public String toString() {        
                return "18 - 23";
        }
        public AgeRange valueOf (Class enumClass, String name) {
                return A18T023
        }
    },

    .
    .
    .
}

Покупатель, будьте осторожны - не скомпилировано и не протестировано ...

Механизм для toString() и valueOf() является документированной частью API

Должен ли этот второй быть методом valueOf?

iny 27.10.2008 18:14

-1 Если не ошибаюсь, совет по valueOf здесь ... неправильный, мягко говоря ;-). valueOf() статичен и не используется в теле конкретного значения перечисления. И даже после того, как все это будет исправлено, «правильная» реализация будет неправильной, поскольку компилятор не допускает статического переопределения на static public valueOf(String). Обычное решение - просто не использовать valueOf - используйте другое имя.

Ed Staub 26.01.2012 18:50
Ответ принят как подходящий

Самый лучший и простой способ сделать это так:

public enum AgeRange {
    A18TO23 ("18-23"),
    A24TO29 ("24-29"),
    A30TO35("30-35");

    private String value;

    AgeRange(String value){
        this.value = value;
    }

    public String toString(){
        return value;
    }

    public static AgeRange getByValue(String value){
        for (final AgeRange element : EnumSet.allOf(AgeRange.class)) {
            if (element.toString().equals(value)) {
                return element;
            }
        }
        return null;
    }
}

Затем вам просто нужно вызвать метод getByValue() с входом String в нем.

Я согласен с тем, что неплохо поместить значение в конструктор. Для очень больших перечислений (а они действительно должны быть довольно большими) имеет смысл использовать карту. Я бы лично вернулся и изнутри цикла, но тогда я никогда не был фанатом «возврата из одного места независимо от читабельности» :)

Jon Skeet 27.10.2008 19:12

Еще один момент - было бы лучше использовать EnumSet.allOf вместо AgeRange.values ​​(), иначе вы создадите новый массив для каждого вызова.

Jon Skeet 27.10.2008 19:13

Очень интересно. Многое из того, что происходит в коде, для меня в новинку. Спасибо за совет!

Kevin 28.10.2008 04:33

вместо вашего метода, getByValue(String), не следует ли вам просто делегировать присущий перечислению valueOf(String)? ссылка: stackoverflow.com/questions/11914792/…

liltitus27 19.11.2013 22:48

Вы могли бы попробовать что-то вроде следующего?

static AgeRange fromString(String range) {
    for (AgeRange ageRange : values()) {
        if (range.equals(ageRange.toString())) {
            return ageRange;
        }
    }
    return null;   
}

Или, как предлагали другие, с использованием подхода кеширования:

private static Map<String, AgeRange> map;

private static synchronized void registerAgeRange(AgeRange ageRange) {
    if (map == null) {
        map = new HashMap<String, AgeRange>();
    }
    map.put(ageRange.toString(), ageRange);
}

AgeRange() {
    registerAgeRange(this);
}

static AgeRange fromString(String range) {
    return map.get(range);
}

Согласно действующему пункту 30 java (2nd ed), это может быть (это намного быстрее, чем цикл)

public enum AgeRange {
       A18TO23("18-23"),
       A24TO29("24-29"),
       A30TO35("30-35");

       private final String value;

       AgeRange(String value){
          this.value = value;
       }

       @Override public String toString(){
           return value;
       }

       private static final Map<String, AgeRange> stringToEnum =
           new HashMap<String, AgeRange>();

       static {
           for (AgeRange r : values()) {
               stringToEnum.put(r.toString(), r);
           }
       }

       public static AgeRange getByValue(String value){
           return stringToEnum.get(value);
       }
}

Другие вопросы по теме