Java枚举valueOf()有多个值?

问题描述 投票:44回答:6

我在使用Enums的Java中遇到了问题。我已阅读有关为Enums分配值参数的文档。但是,我的问题是多值的问题,是否可能?

这就是我想要实现的:我有一个语言枚举。每种语言都由其名称和一些较短的别名表示(并非总是如此,并且并不总是相同的别名数)

这是一个例子:

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

我可以像这样定义一个枚举,并通过调用Language.valueOf()获得正确的枚举值吗?

java enums
6个回答
64
投票

这可能与您尝试实现的类似。

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;
}

15
投票

将字符串映射到枚举值通常是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.toUpperCase()); 
    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,更具体的HashMapHashMap提供了一个快速访问别名的途径,也很容易成长。每当我们考虑“索引”某些东西时,HashMap可能应该是我们的首选。

请注意,对于透明使用,我们存储枚举常量本身的名称(通过name()方法检索)和所有别名。我们可以通过首先尝试使用内置的valueOf静态方法进行查找来实现这一点。这是一个设计选择,但我们可能不得不处理其他异常等。


3
投票

简而言之,没有。

valueOf()方法的参数必须只是枚举常量类型的String。所以它不能改变,或查找可能的值。见JavaDoc

您需要编写自己的实用程序方法以返回给定值的正确枚举类型。


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
投票

哇,真的很快回复:)谢谢你们。

安迪是对的。我想调用Language.valueOf(“eng”)或Language.valueOf(“english”)并将Language.English作为返回值。

我已经有一个实用程序功能,但它不是很好。切换函数,检查字符串值并返回适当的枚举实例。

但是有很多代码重写(我有cca 30-40语言)。如果我想添加一种语言,我必须将它添加到枚举,并在实用程序类中实现一个新的检查。

我会尝试Flavios方法。只有一个问题。你的构造函数,不应该吗?

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

0
投票

或者添加一个方法,如果结构更复杂,你的枚举和构造函数可以更干净:

public Language getLanguage(String code){
  switch(code){
    case "en":
    case "en_GB":
    ...
    case "eng":
      return ENGLISH;
    case "rus":
    case "russian":
      return RUSSIAN;
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.