Java枚举字符串匹配

3

我有一个枚举类型,如下所示:

public enum ServerTask {

HOOK_BEFORE_ALL_TASKS("Execute"),
COPY_MASTER_AND_SNAPSHOT_TO_HISTORY("Copy master db"),
PROCESS_CHECKIN_QUEUE("Process Check-In Queue"),
...
}

我有一个字符串(假设为string =“Execute”),我想根据枚举中与之匹配的字符串将其变成ServerTask枚举的实例。是否有比在要匹配的字符串和枚举中的每个项目之间进行相等性检查更好的方法?因为我的枚举相当大,所以这似乎需要很多if语句。


4
你只需要在循环ServerTask.values()时使用单个if语句即可 :) - NiziL
你是在检查枚举的名称(例如 HOOK_BEFORE_ALL_TASKS)还是该参数的值("Execute")?如果是参数,则如果您提供getter代码或其名称(如果不是 private),这将有所帮助。 - Captain Man
4个回答

5

在某个级别上,您将不得不遍历您拥有的所有枚举集,并通过映射结构(初始人口)或通过基本循环将它们进行比较。

使用基本循环实现起来相对容易,因此我不明白为什么您不想采用这种方法。下面的代码片段假设字段名为friendlyTask

public static ServerTask forTaskName(String friendlyTask) {
    for (ServerTask serverTask : ServerTask.values()) {
        if(serverTask.friendlyTask.equals(friendlyTask)) {
            return serverTask;
        }
    }
    return null;
}

这种方法的缺点是数据不会存储在内部,而且根据您实际拥有的枚举数量以及想要调用此方法的次数,它的性能略低于使用地图进行初始化。
然而,这种方法是最直接的。如果您发现自己处于有数百个枚举的位置(甚至超过20个对我来说都有些可疑),请考虑这些枚举表示的内容以及应该如何将其分解出来。

1
创建静态反向查找映射。
public enum ServerTask {

  HOOK_BEFORE_ALL_TASKS("Execute"),
  COPY_MASTER_AND_SNAPSHOT_TO_HISTORY("Copy master db"),
  PROCESS_CHECKIN_QUEUE("Process Check-In Queue"),
  ...
  FINAL_ITEM("Final item");

  // For static data always prefer to use Guava's Immutable library
  // http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/ImmutableMap.html

  static ImmutableMap< String, ServerTask > REVERSE_MAP;

  static
  {
    ImmutableMap.Builder< String, ServerTask > reverseMapBuilder =
      ImmutableMap.builder( );

    // Build the reverse map by iterating all the values of your enum
    for ( ServerTask cur : values() )
    {
       reverseMapBuilder.put( cur.taskName, cur );
    }

    REVERSE_MAP = reverseMapBuilder.build( );
  }

  // Now is the lookup method
  public static ServerTask fromTaskName( String friendlyName ) 
  {
    // Will return ENUM if friendlyName matches what you stored
    // with enum
    return REVERSE_MAP.get( friendlyName );
  }

}

Maps.uniqueIndex() 会使代码更简洁。 - Matt Ball
3
你能否添加一些评论来说明正在发生的事情? - GregH
@jeremy。有什么不清楚的吗?如果您问我会回答的。 - Alexander Pogrebnyak
3
不是因为暴力,而是因为你只是把代码倒出来了,没有解释这些代码是如何工作的。Jeremy请求评论以说明正在发生的事情,我认为很明显他不仅仅是在寻找解决方案,他实际上想要理解你为什么这样做以及它是如何工作的。 - Aify

1
如果您需要经常从字符串中获取枚举值,则像Alexander建议的创建反向映射可能是值得的。
如果只需要执行一两次,则使用单个if语句循环遍历值可能是最佳选择(如Nizil的评论所暗示的那样)。
for (ServerTask task : ServerTask.values())
{
    //Check here if strings match
}

然而,有一种方法可以完全不需要迭代值。如果您可以确保enum实例的名称和其String值相同,则可以使用以下方法:

ServerTask.valueOf("EXECUTE")

这将为您提供ServerTask.EXECUTE。

有关更多信息,请参阅this答案。

话虽如此,除非您可以接受实例具有与其标识符相同的字符串表示形式并且您的应用程序具有关键性能问题(这种情况最常见不是),否则我不建议采用此方法。


ServerTask.valueOf(...) 是你正在寻找的。如果枚举全部大写,那么你也可以使用 ServerTask.valueOf(input.toUpperCase()); - Jamie
@Jamie 在他的例子中,枚举实例标识符和它们的字符串值不匹配(不仅仅是大小写)。例如,HOOK_BEFORE_ALL_TASKS 的字符串值为 "EXECUTE" - Srini

0
你可以编写一个像这样的方法:
static ServerTask getServerTask(String name)
{
    switch(name)
    {
         case "Execute": return HOOK_BEFORE_ALL_TASKS;
         case "Copy master db": return COPY_MASTER_AND_SNAPSHOT_TO_HISTORY;
         case "Process Check-In Queue": return PROCESS_CHECKIN_QUEUE;
    }
}

这个方案比@Alexander_Pogrebnyak的方案要小,但不像后者那样自动化。如果枚举发生了改变,您需要更新switch语句。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接