2010-11-16 4 views
41

У меня проблема с Java с помощью Enums. Я прочитал документацию о присвоении параметрам значения Enums. Но, мой вопрос в том, что о нескольких значениях, возможно ли это?Значение перечисления Java enOp() с несколькими значениями?

Этого, чего я хотел бы достичь: У меня есть Enum для языков. Каждый язык представлен своим именем и более коротких псевдонимами (не всегда, и не всегда то же самое число псевдонимов)

Вот пример:

public enum Language{ 
English("english", "eng", "en", "en_GB", "en_US"), 
German("german", "de", "ge"), 
Croatian("croatian", "hr", "cro"), 
Russian("russian") 
} 

Могу ли я просто определить Enum, как это и получить правильные значения перечисления, вызывая Language.valueOf() ???

+0

I Рекомендуем посмотреть мои статьи: http://java.dzone.com/articles/enum-tricks-customized-valueof и http://java.dzone.com/articles/enum-tricks-hierarchical-data Хотя я не уверен, что понимаю, что вы действительно хотите, я считаю, что хотя бы одна из этих статей содержит ответ на ваш вопрос. – AlexR

ответ

59

Возможно, это похоже на то, чего вы пытаетесь достичь.

public enum Language{ 
    English("english", "eng", "en", "en_GB", "en_US"), 
    German("german", "de", "ge"), 
    Croatian("croatian", "hr", "cro"), 
    Russian("russian"); 

    private final List<String> values; 

    Language(String ...values) { 
     this.values = Arrays.asList(values); 
    } 

    public List<String> getValues() { 
     return values; 
    } 
} 

Помните, что перечисления - это класс, подобный другим; English("english", "eng", "en", "en_GB", "en_US") вызывает конструктор перечисления.

Затем вы можете получить значение перечисления, соответствующее строке, с помощью метода поиска (вы можете поместить его как статический метод в перечисление снова).

public static Language find(String name) { 
    for (Language lang : Language.values()) { 
     if (lang.getValues().contains(name)) { 
      return lang; 
     } 
    } 
    return null; 
} 
+2

Я мог бы неправильно понять это, но я думаю, что он хочет иметь возможность делать Language.valueOf («eng») или Language.valueOf («english») и возвращать тот же экземпляр enum. – Andy

+0

Хорошо, что невозможно с помощью метода defaul valueOf; Я отредактировал ответ, чтобы включить метод для получения этого эффекта. – Flavio

+0

Да, я тоже был смущен, действительно, это умная идея, я думаю, но это невозможно. – Andy

3

Короче говоря, нет.

Параметр метода valueOf() должен быть только строкой константного типа enum. Поэтому он не может меняться или искать возможные значения. См. JavaDoc.

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

1

Вау, очень быстрый ответ :) Спасибо, ребята.

Энди справа. Я хочу вызвать Language.valueOf ("eng") или Language.valueOf ("english") и получить Language.English в качестве возврата.

У меня уже есть функция утилиты, которая делает это, но это не очень приятно. Функция переключателя, которая проверяет строковые значения и возвращает соответствующий экземпляр enum.

Но есть много перезаписи кода (у меня есть 30-40 языков). И если я хочу добавить язык, я должен добавить его в enum и реализовать новую проверку в классе утилиты.

Я попробую подход Флавиоса. Только один вопрос. Ваш конструктор, не так ли?

Language(List<String> values) { 
    this.values = Arrays.asList(values); 
} 
+0

Если вы используете свой конструктор (вы должны удалить вызов 'Arrays.asList', чтобы он скомпилировался), экземпляры должны были быть созданы с «English (Arrays.asList (« английский »,« eng »,« en »,« en_GB »,« en_US »)). Вы также можете сохранить значения в виде простого массива вместо списка ... однако поиск будет несколько более неудобным. – Flavio

2

Нормализация данные:

public enum LanguageCode 
{ 
    ENGLISH, 
    GERMAN, 
    CROATIAN, 
    RUSSIAN, 
    // ... 
} 
// (add whatever initialization you want to that 

Тогда

public enum Language{ 
    english(ENGLISH), 
    eng(ENGLISH), 
    en(ENGLISH), 
    en_GB(ENGLISH), 
    // ... 
} 

т.д.

+1

Хммм ... Я не думаю, что это сработает. LanguageEnum членов тогда будет английский, eng, en, en_GB ... , а не АНГЛИЙСКИЙ, НЕМЕЦКИЙ ... – zolakt

10

Отображение строки в значение перечисления, как правило, то, что valueOf статический метод делает для вы.Поэтому, если вы хотите добиться этого с помощью синонимов, вам придется разработать нечто подобное. Однако мы не хотим указывать, что мы можем переопределить статический метод, поэтому для этой цели мы просто назовем его другим: fromString должен быть уместным.

public enum Language { 
    ENGLISH("eng", "en", "en_GB", "en_US"), 
    GERMAN("de", "ge"), 
    CROATIAN("hr", "cro"), 
    RUSSIAN("ru"), 
    BELGIAN("be",";-)"); 

    static final private Map<String,Language> ALIAS_MAP = new HashMap<String,Language>(); 
    static { 
    for (Language language:Language.values()) { 
     // ignoring the case by normalizing to uppercase 
     ALIAS_MAP.put(language.name().toUpperCase(),language); 
     for (String alias:language.aliases) 
     ALIAS_MAP.put(alias.toUpperCase(),language); 
    } 
    } 

    static public boolean has(String value) { 
    // ignoring the case by normalizing to uppercase 
    return ALIAS_MAP.containsKey(value.toUpperCase()); 
    } 

    static public Language fromString(String value) { 
    if (value == null) throw new NullPointerException("alias null"); 
    Language language = ALIAS_MAP.get(value); 
    if (language == null) 
     throw new IllegalArgumentException("Not an alias: "+value); 
    return language; 
    } 

    private List<String> aliases; 
    private Language(String... aliases) { 
    this.aliases = Arrays.asList(aliases); 
    } 
} 

В пользу этого типа реализации мы можем, как показано, также легко реализовать статический метод has, чтобы проверить, является ли данный псевдонимом является частью множества значений перечисления. В то же время мы применили несколько хороших соглашений об именах:

  • значения перечисления идут в верхнем регистре, чтобы указать, что они находятся в актуальном статическом финале (экземпляры однопользовательского режима).
  • в то же время, мы также ставим все остальные статические финалы всех шапок.

Обратите внимание, что мы не должны повторять название самого значения перечисления: мы всегда учитываем это собственное имя автоматически (добавляется к ALIAS_MAP), а сверху нормировать все в верхний регистр, чтобы сделать его чувствительно к регистру ,

Кажется большим, но при использовании перечисления, это выглядит довольно:

public void main() { 
    Language myLanguage = Language.fromString("en_GB"); 
    if (myLanguage == Language.ENGLISH) { 
    System.out.println("Yes, I know, you understand English!"); 
    } 
} 

Подложка контейнер для псевдонимов является Map, HashMap быть более конкретными. HashMap обеспечивает быстрый доступ к псевдонимам, а также легко растет. Всякий раз, когда мы думаем о «индексировании» чего-то, вероятно, наш первый выбор должен быть HashMap.

Обратите внимание, что для прозрачного использования мы сохраняем как имя самой константы перечисления (полученное методом name()), так и все псевдонимы. Мы могли бы реализовать это по-другому, сначала попытавшись выполнить поиск, используя встроенный статический метод valueOf. Это выбор дизайна, но мы бы потенциально иметь дело с дополнительными исключениями и т.д.

0

В качестве альтернативы добавить метод, так что ваши перечисления и конструктор могут быть более чистыми, если структура более сложная:

public Language getLanguage(String code){ 
    switch(code){ 
    case "en": 
    case "en_GB": 
    ... 
    case "eng": 
     return ENGLISH; 
    case "rus": 
    case "russian": 
     return RUSSIAN; 
    } 
} 
Смежные вопросы