Учитывая следующее перечисление 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?
Спасибо!




Вы всегда можете создать сопоставление от строки к значению - делайте это статически, поэтому вам нужно сопоставить ее только один раз, предполагая, что возвращаемая строка остается неизменной с течением времени. Насколько я знаю, здесь нет ничего встроенного.
Я тоже рассматриваю этот метод, но в этом перечислении у меня всего около 15 значений. Еще эффективнее создать карту?
Скорее всего, нет, если честно. Хеш-таблицы отлично подходят для больших объемов данных, но я подозреваю, что сравнение 15 значений (в худшем случае) будет примерно таким же быстрым, как получение хэш-кода, поиск нужного сегмента и т. д.
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?
-1 Если не ошибаюсь, совет по valueOf здесь ... неправильный, мягко говоря ;-). valueOf() статичен и не используется в теле конкретного значения перечисления. И даже после того, как все это будет исправлено, «правильная» реализация будет неправильной, поскольку компилятор не допускает статического переопределения на static public valueOf(String). Обычное решение - просто не использовать valueOf - используйте другое имя.
Самый лучший и простой способ сделать это так:
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 в нем.
Я согласен с тем, что неплохо поместить значение в конструктор. Для очень больших перечислений (а они действительно должны быть довольно большими) имеет смысл использовать карту. Я бы лично вернулся и изнутри цикла, но тогда я никогда не был фанатом «возврата из одного места независимо от читабельности» :)
Еще один момент - было бы лучше использовать EnumSet.allOf вместо AgeRange.values (), иначе вы создадите новый массив для каждого вызова.
Очень интересно. Многое из того, что происходит в коде, для меня в новинку. Спасибо за совет!
вместо вашего метода, getByValue(String), не следует ли вам просто делегировать присущий перечислению valueOf(String)? ссылка: stackoverflow.com/questions/11914792/…
Вы могли бы попробовать что-то вроде следующего?
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);
}
}
Это гораздо лучший способ справиться с этим. Затем карта создается, когда есть перечисление, и работает намного быстрее, чем итерация массива.