将枚举中的所有名称作为String[]获取

130

获得枚举元素名称的最简单且/或最短的方法是什么,使其作为String数组返回?

这意味着,例如,如果我有以下枚举:

public enum State {
    NEW,
    RUNNABLE,
    BLOCKED,
    WAITING,
    TIMED_WAITING,
    TERMINATED;

    public static String[] names() {
        // ...
    }
}

names()方法将返回数组{ "NEW", "RUNNABLE", "BLOCKED", "WAITING", "TIMED_WAITING", "TERMINATED" }


2
为什么没有一个本地的Enum方法可以完全做到这一点,我不明白...还有一个get(index)来简化对value()的获取。 - marcolopes
26个回答

131

这是一个用于任何enum类的一行代码:

public static String[] getNames(Class<? extends Enum<?>> e) {
    return Arrays.stream(e.getEnumConstants()).map(Enum::name).toArray(String[]::new);
}

Java 8之前仍然可以使用一行代码,尽管不够优雅:

public static String[] getNames(Class<? extends Enum<?>> e) {
    return Arrays.toString(e.getEnumConstants()).replaceAll("^.|.$", "").split(", ");
}

你会像这样调用它:

String[] names = getNames(State.class); // any other enum class will work

如果你只是想要一个针对硬编码枚举类的简单解决方案:

public static String[] names() {
    return Arrays.toString(State.values()).replaceAll("^.|.$", "").split(", ");
}

2
不是最快的方法,但正则表达式很好。 - ceklock
4
在Java 8解决方案中,在方法范围之外,您可以使用YourEnumName.values()代替e.getEnumConstants() - Eido95
1
@Eido95 使用 YourEnumName.values() 调用了类上的静态方法,这不能被用于任何枚举。使用 getEnumConstants() 可以适用于任何枚举类。这个方法的想法是重新创建一个实用方法,你可以像答案的最后一行那样调用它。 - Bohemian
不需要使用Streams。一个简单的for循环和一个临时数组就可以解决问题。 - bezbos.
@BoškoBezik 没有必要为任何事情使用流,但它们可以使代码更整洁,希望更容易阅读,这是代码的目的。 - Bohemian
显示剩余3条评论

66
创建一个 String[] 数组用于存储名称,调用静态的 values() 方法获取所有枚举值,然后遍历这些值并将它们添加到名称数组中。
public static String[] names() {
    State[] states = values();
    String[] names = new String[states.length];

    for (int i = 0; i < states.length; i++) {
        names[i] = states[i].name();
    }

    return names;
}

9
为什么要调用values()13次,每次生成一个新数组,而不是在本地变量中缓存该数组?为什么要使用可重写的toString()而不是name() - JB Nizet
@JBNizet 哈哈,我实际上在我的IDE中尝试过这个,但是我太懒了,不想创建一个状态数组,呵呵,无论如何,我现在已经编辑好了 :) - PermGenError
2
你仍然没有返回名称,而是返回了toString()的值。 - JB Nizet
1
我接受了这个答案,但我提交了一个编辑,改进了代码,使其更易于阅读。 - Konstantin
@PermGenError,我想知道如何在将字符串数组与枚举数组进行比较后返回值(英语,L1),其中L1是该值。例如,字符串数组包含英语等内容,但如果它与枚举中的内容匹配,我希望返回L1,L2等列表。 - Karen Goh
显示剩余3条评论

24

如果您可以使用Java 8,那么这个方法很好用(是Yura建议的替代方法,更有效率):

public static String[] names() {
    return Stream.of(State.values()).map(State::name).toArray(String[]::new);
}

20

这里有一个优雅的解决方案,使用Apache Commons Lang 3

EnumUtils.getEnumList(State.class)

虽然它返回一个List,但你可以轻松地用 list.toArray() 将其转换为数组。


7
EnumUtils.getEnumList(enumClass) 返回的是枚举值,而不是字符串。你可以使用 EnumUtils.getEnumMap(enumClass).keySet(),但是顺序可能会不同。 - Dan Halbert

13

使用Java 8:

Arrays.stream(MyEnum.values()).map(Enum::name)
                    .collect(Collectors.toList()).toArray();

2
虽然这个实现可能有效,但它相当低效,首先创建一个ArrayList,添加所有元素,然后再创建一个数组并再次复制所有内容。 - Daniel Bimschas
很快,“每个人”都将使用流来完成最基本的操作……这并不是一个非常好的想法。 - marcolopes
考虑到枚举中元素的数量通常相对较少,我认为Yura的解决方案对于许多用例来说都是可以的。当然,这将取决于具体情况... - stefan.m

6
我会这样写:

我会这样写

public static String[] names() {

    java.util.LinkedList<String> list = new LinkedList<String>();
    for (State s : State.values()) {
        list.add(s.name());
    }

    return list.toArray(new String[list.size()]);
}

4

其他方法:

第一个方法

Arrays.asList(FieldType.values())
            .stream()
            .map(f -> f.toString())
            .toArray(String[]::new);

其他方法

Stream.of(FieldType.values()).map(f -> f.toString()).toArray(String[]::new);

2
这种情况下toString()可以工作,但在一般情况下它不行,因为toString()可以被覆盖。使用.name()可可靠地获取实例的名称作为字符串。 - Bohemian

3

找到了简单的解决方案

Arrays.stream(State.values()).map(Enum::name).collect(Collectors.toList())

3

1
虽然这并不特别重要,但在这种情况下,普通的for循环比foreach循环提供更好的性能。此外,values()被调用两次,而实际上只需要调用一次。 - FThompson
1
@Vulcan,我认为只有在运行数十万次时,性能才会成为一个问题。此外,values()是编译器生成的方法,所以我猜它已经被优化得很好了。最后,我记得在某个地方读到过,增强型for循环比标准的递增for循环更高效,但是——这并不重要 - Konstantin
@Konstantin 考虑到 Java 中的 foreach 循环是使用标准 for 循环实现的,所以无论你在哪里读到 foreach 循环更高效的说法都是不正确的。 - sage88
1
@sage88 我指的是使用数字索引检索元素并在每个循环中递增的for循环。例如: for (int i = 0; i < a.length; i++) /* do stuff */; 在这种情况下,for-each循环实际上更有效率。快速搜索SO得到了这个结果:https://dev59.com/T3I95IYBdhLWcg3w3iHG - Konstantin
@Konstantin 任何时候,当您拥有一个允许随机访问的数据结构,例如枚举值返回数组时,使用C风格的for循环比使用for each循环更快。for each循环必须生成迭代器,这使得它变慢。您发布的链接提供了使用标准for循环在链表上使用get(i)的示例,这当然更糟糕。当使用非随机访问数据结构时,for each循环更快,但在数组上具有更大的开销。此外,由于它是原始数组而不是ArrayList,因此没有来自.size()的性能损失。 - sage88
虽然我应该说我之前错了,因为每个循环并不使用标准的for循环,而是使用迭代器。 - sage88

2

常规方式(俗语):

String[] myStringArray=new String[EMyEnum.values().length];
for(EMyEnum e:EMyEnum.values())myStringArray[e.ordinal()]=e.toString();

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