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


95

将枚举元素的名称获取为Strings 数组的最简单和/或最短的方法是什么?

我的意思是,例如,如果我有以下枚举:

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 2014年

Answers:


91

这是任何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

2
在Java 8解决方案中,在方法范围之外,而不是e.getEnumConstants()您可以使用YourEnumName.values()
Eido95 '16

1
@ Eido95使用YourEnumName.values()正在类上调用静态方法,该方法不能用于任何枚举。使用getEnumConstants()适用于任何枚举类。使用此方法的想法是重新创建一个实用程序方法,您可以像回答的最后一行一样调用它。
波希米亚

如果要为枚举添加自定义标签,请在枚举类中重写toString()。
ralphgabb18年

你能解释一下Class<? extends Enum<?>> e吗?
卡马吉登

63

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 heheh,我实际上在我的IDE中尝试过这种方法,并且懒惰地创建了一个State数组,我想,嘻嘻,无论如何现在都在编辑它:)
PermGenError 2012年

2
您仍然没有返回名称,而是返回toString()值。
JB Nizet

@JBNizet嗯,TBH,我确实知道name()直到现在才有一种方法。我多么愚蠢:P感谢您告诉我:)
PermGenError 2012年

1
我接受了这个答案,但是我提交了一个可以改善代码的编辑,以便于阅读。
康斯坦丁2012年

14

这是一个使用Apache Commons Lang 3的优雅解决方案:

EnumUtils.getEnumList(State.class)

尽管它返回一个列表,但是您可以使用 list.toArray()


5
EnumUtils.getEnumList(enumClass)返回枚举值,而不是字符串。您可以使用EnumUtils.getEnumMap(enumClass).keySet(),但是顺序可能有所不同。
丹·哈尔伯特

11

如果您可以使用Java 8,则效果很好(替代Yura的建议,效率更高):

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

9

使用Java 8:

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

2
尽管可能可行,但此实现效率很低,首先创建一个ArrayList,添加所有元素,然后创建一个数组,然后再次复制所有内容。
Daniel Bimschas 2015年

不久以后,“每个人”都将使用流来完成最基本的操作……这不是一个好主意。
marcolopes 2015年

考虑到枚举中的元素数量通常很少的事实,我认为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()]);
}

3

这样的事情会做:

public static String[] names() {
  String[] names = new String[values().length];
  int index = 0;

  for (State state : values()) {
    names[index++] = state.name();
  }

  return names;
}

该文档建议在大多数情况下使用toString()而不是name(),但是您已经在此处明确要求输入名称。


1
尽管并不特别重要,但在这种情况下,常规的for循环比foreach循环提供更好的性能。另外,values()在仅需要调用一次时被调用两次。
FThompson,2012年

1
@Vulcan我认为,如果运行了数十万次,性能只会成为问题。此外,它values()是由编译器生成的方法,因此我猜它已经非常优化。最后,我记得在某处读过,for-each循环比标准的增量for循环更有效,但是再说一次- 没关系
康斯坦丁

@Konstantin考虑到Java中的foreach循环是使用标准的for循环实现的,因此,无论您读到哪个foreach循环都更加高效,都是不正确的。
sage88

1
@ sage88我指的是for循环,其中您使用数字索引检索元素,该数字索引在每个循环中递增。例如:for (int i = 0; i < a.length; i++) /* do stuff */;在这种情况下,换每个循环,事实上,更有效。对此事快速SO搜索给了我们这样的:stackoverflow.com/questions/2113216/...
康斯坦丁

@Konstantin每当您拥有允许随机访问的数据结构(例如枚举值返回数组的情况)时,C样式的for循环都会比对for每个循环使用更快。for每个循环必须生成一个迭代器,这会使它变慢。您发布的链接给出了一个使用get(i)在链表上使用标准for循环的示例,这当然会更糟。使用非随机访问数据结构时,for循环更快,但是在阵列上开销更大。另外,由于它是原始数组,而不是ArrayList,因此.size()不会对性能造成任何影响。
sage88

3

另一种方式:

第一

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

另一种方式

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

1
这种情况下toString()有效,但在一般情况下则无效,因为toString()可以被覆盖。使用.name()可靠地获取实例名称为一个字符串。
波希米亚

2

我的解决方案是使用字符串(不是最快的方法,但是很紧凑):

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

    public static String[] names() {
        String valuesStr = Arrays.toString(State.values());
        return valuesStr.substring(1, valuesStr.length()-1).replace(" ", "").split(",");
    }
}

和java7兼容!
Aquarius Power

1

我会这样做(但我可能会将名称设为不可修改的集合,而不是数组):

import java.util.Arrays;
enum State {
    NEW,RUNNABLE,BLOCKED,WAITING,TIMED_WAITING,TERMINATED;
    public static final String[] names=new String[values().length];
    static {
        State[] values=values();
        for(int i=0;i<values.length;i++)
            names[i]=values[i].name();
    }
}
public class So13783295 {
    public static void main(String[] args) {
        System.out.println(Arrays.asList(State.names));
    }
}

如果需要重复获取枚举名称,我也将执行类似的操作,但是由于该names()方法仅被少量调用,因此我认为当场生成数组是可以的。
康斯坦丁

1

我有相同的需求,并使用通用方法(在ArrayUtils类内部):

public static <T> String[] toStringArray(T[] array) {
    String[] result=new String[array.length];
    for(int i=0; i<array.length; i++){
        result[i]=array[i].toString();
    }
    return result;
}

并在枚举内定义一个STATIC ...

public static final String[] NAMES = ArrayUtils.toStringArray(values());

Java枚举确实错过了names()和get(index)方法,它们确实很有帮助。


1

普通方式(双关语意):

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

1

我对@Bohemian的解决方案做了一些测试。当使用朴素循环时,性能会更好。

public static <T extends Enum<?>> String[] getEnumNames(Class<T> inEnumClass){
    T [] values = inEnumClass.getEnumConstants();
    int len = values.length;
    String[] names = new String[len];
    for(int i=0;i<values.length;i++){
        names[i] = values[i].name();
    }
    return names;
}

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

您应该提供有关绩效的统计数据,然后人们可以自己判断绩效损失是否重大。我想大多数人的枚举值不会超过100或1000+。
Rauni Lillemets '18


0

如果您想最短,可以尝试

public static String[] names() {
    String test = Arrays.toString(values());
    return text.substring(1, text.length()-1).split(", ");
}

不是最短的:)请参阅我的单线答复(仍然只调用vales()一次)
波西米亚式

0

只是想一想:也许您不需要创建一种方法来将枚举值作为字符串数组返回。

为什么需要字符串数组?也许您只需要在使用它们时就转换它们,如果需要的话。

例子:

for (State value:values()) {
    System.out.println(value); // Just print it.
}

for (State value:values()) {
    String x = value.toString(); // Just iterate and do something with x.
}

// If you just need to print the values:
System.out.println(Arrays.toString(State.values()));

0

在Java 7或更早版本中执行此操作的另一种方法是使用Guava:

public static String[] names() {
    return FluentIterable.from(values()).transform(Enum::name).toArray(String.class);
}

0

试试这个:

public static String[] vratAtributy() {
    String[] atributy = new String[values().length];
    for(int index = 0; index < atributy.length; index++) {
        atributy[index] = values()[index].toString();
    }
    return atributy;
}

0

您可以将枚举值放入字符串列表并转换为数组:

    List<String> stateList = new ArrayList<>();

            for (State state: State.values()) {
                stateList.add(state.toString());
            }

    String[] stateArray = new String[stateList.size()];
    stateArray = stateList.toArray(stateArray);

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.