Java 枚举 valueOf() 具有多个值?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4197988/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 14:29:01  来源:igfitidea点击:

Java enum valueOf() with multiple values?

javaenums

提问by zolakt

I have a problem in Java using Enums. I have read the documentation about assigning value parameters to Enums. But, my question is what about multiple values, is it possible?

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

This what I would like to achieve: I have an Enum for languages. Each language is represented by its name and some shorter aliases (not always, and not always the same number of aliases)

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

Here is an example:

下面是一个例子:

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

Can I just define an Enum like this and get the right enum values by calling Language.valueOf() ???

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

回答by Flavio

This is probably similar to what you're trying to achieve.

这可能与您要实现的目标类似。

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

Remember enums are a class like the others; English("english", "eng", "en", "en_GB", "en_US")is calling the enum constructor.

请记住,枚举和其他类一样是一个类;English("english", "eng", "en", "en_GB", "en_US")正在调用枚举构造函数。

You could then retrieve the enum value corresponding to a string through a search method (you can put it as a static method in the enum again).

然后,您可以通过搜索方法检索与字符串对应的枚举值(您可以再次将其作为静态方法放入枚举中)。

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

回答by Andy

In short, no.

简而言之,没有。

The parameter for the valueOf() method must be only the String of the enum constant type. So it cannot vary, or lookup possible values. See the JavaDoc.

valueOf() 方法的参数只能是枚举常量类型的字符串。所以它不能变化,也不能查找可能的值。请参阅JavaDoc

You need to write your own utility method to return the proper enum type for the given values.

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

回答by zolakt

Wow, really quick reply :) Thanks guys.

哇,真的很快回复:) 谢谢大家。

Andy is right. I want to call Language.valueOf("eng") or Language.valueOf("english") and get Language.English as return.

安迪是对的。我想调用 Language.valueOf("eng") 或 Language.valueOf("english") 并获得 Language.English 作为回报。

I already have a utility function that does this, but it's not very nice. Switch function that checks string values and return appropriate enum instance.

我已经有一个实用函数可以做到这一点,但它不是很好。检查字符串值并返回适当的枚举实例的开关函数。

But there is a lot of code rewriting (I have cca 30-40 languages). And if I want to add a language, I have to add it to enum, and implement a new check in the utility class.

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

I'll try Flavios approach. Just one question. Your constructor, shouldn't it be?

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

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

回答by user207421

Normalize the data:

规范化数据:

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

Then

然后

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

etc.

等等。

回答by YoYo

Mapping a string to a enum value, is typically what the valueOfstatic method is doing for you. So if you want to accomplish this with the use of synonyms, you will have to develop something similar. However we do not want to give the presence that we can override a static method, so we just name it different for this purpose: fromStringshould be appropriate.

将字符串映射到枚举值,通常是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); 
  } 
} 

As a benefit of this type of implementation we can, as demonstrated, also easily implement the hasstatic method to test if a given alias is part of the enum value set. At the same time, we applied some good naming conventions:

作为这种类型实现的一个好处,如演示的那样,我们还可以轻松实现has静态方法来测试给定的别名是否是枚举值集的一部分。同时,我们应用了一些好的命名约定:

  • the enum values go in uppercase, to indicate that they are in actuality static finals (singleton instances).
  • at the same time, we also put all the other static finals all caps.
  • 枚举值以大写形式显示,以表明它们实际上是静态最终结果(单例实例)。
  • 同时,我们也将所有其他静态决赛全部大写。

Note that we do not have to repeat the name of the enum value itself: we always consider it's own name automatically (gets added to the ALIAS_MAP), and on top we normalize everything to uppercase to make it case insensitive.

请注意,我们不必重复枚举值本身的名称:我们总是自动考虑它自己的名称(被添加到 ALIAS_MAP 中),并且最重要的是我们将所有内容标准化为大写,使其不区分大小写。

Seems big, but while using the enum, it looks pretty:

看起来很大,但是在使用枚举时,它看起来很漂亮:

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

The backing container for the aliases is a Map, a HashMapto be more specific. The HashMapprovides a fast access path to the aliases, and is also easy to grow. Whenever we think about 'indexing' something, likely a HashMapshould be our first choice.

别名的后备容器是 a MapHashMap更具体地说是 a 。在HashMap提供给别名快速访问路径,也容易生长。每当我们考虑“索引”某些东西时,可能 aHashMap应该是我们的首选。

Note that for transparent use, we store both the name of the enum constant itself (retrieved through the name()method), and all the aliases. We could have implemented this differently by first attempting to do the lookup using the built-in valueOfstatic method. It is a design choice, but we would potentially have to deal with additional exceptions etc.

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

回答by CsBalazsHungary

Alternatively add a method, so your enums and constructor can be more clean if the structure is more complicated:

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

public Language getLanguage(String code){
  switch(code){
    case "en":
    case "en_GB":
    ...
    case "eng":
      return ENGLISH;
    case "rus":
    case "russian":
      return RUSSIAN;
  }
}