129

What's the easiest and/or shortest way possible to get the names of enum elements as an array of Strings?

What I mean by this is that if, for example, I had the following enum:

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

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

the names() method would return the array { "NEW", "RUNNABLE", "BLOCKED", "WAITING", "TIMED_WAITING", "TERMINATED" }.

Konstantin
  • 2,885
  • 3
  • 22
  • 23
  • 2
    Why there is not a native Enum method that does exactly that it's beyond me... and also a get(index) to simplify the get of value() – marcolopes Mar 06 '14 at 23:04

26 Answers26

130

Here's one-liner for any enum class:

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

Pre Java 8 is still a one-liner, albeit less elegant:

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

That you would call like this:

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

If you just want something simple for a hard-coded enum class:

public static String[] names() {
    return Arrays.toString(State.values()).replaceAll("^.|.$", "").split(", ");
}
Bohemian
  • 412,405
  • 93
  • 575
  • 722
  • 2
    Not the fastest ways to do the job, but nice regex. – ceklock Dec 09 '12 at 03:58
  • 4
    In Java 8 solution, outside a method scope, instead of `e.getEnumConstants()` you may use `YourEnumName.values()` – Eido95 Oct 27 '16 at 12:33
  • 1
    @Eido95 using `YourEnumName.values()` is calling a static method on the class, which cannot be reused for *any* enum. Using `getEnumConstants()` works for *any* enum class. The idea with this method is to recreate a utility method that you can call like the last line of the answer. – Bohemian Oct 27 '16 at 12:44
  • if you want a custom label for your enum, override toString() in your enum class. – ralphgabb Oct 25 '18 at 07:00
  • Can you please explaing `Class extends Enum>> e`? – Carmageddon Jan 20 '20 at 19:55
  • @Carmageddon `Class extends Enum>> e` basically means "any `enum` class", and in more detail means `e` is a `Class` whose type is (or is a subtype of) `Enum>`. All `enum` classes implicitly extend the `Enum` class, whose type is a self-referencing type, ie `Enum>` – Bohemian Jan 20 '20 at 23:33
  • No need to use Streams. A simple `for` loop and a temporary array would do the trick. – bezbos. Apr 23 '21 at 10:23
  • @BoškoBezik there’s no need to ever use streams for anything, but they make the code neater and hopefully easier to read, which is code’s purpose. – Bohemian Apr 23 '21 at 11:15
65

Create a String[] array for the names and call the static values() method which returns all the enum values, then iterate over the values and populate the names array.

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;
}
Konstantin
  • 2,885
  • 3
  • 22
  • 23
PermGenError
  • 45,977
  • 8
  • 87
  • 106
  • 9
    Why call `values()` 13 times, generating a new array each time, instead of caching the array in a local variable? Why use toString(), which is overridable, instead of `name()`? – JB Nizet Dec 09 '12 at 00:12
  • @JBNizet heheh, i actually tried this in my IDE and way to lazy to create an State array i guess, hehe, anyways iedited it now :) – PermGenError Dec 09 '12 at 00:15
  • 2
    You're still not returning the names, but the toString() values. – JB Nizet Dec 09 '12 at 00:17
  • @JBNizet hmm, tbh, i dint really know there was a `name()` method untill now. how stupid of me :P thanks for letting me know :) – PermGenError Dec 09 '12 at 00:19
  • 1
    I accepted this answer, but I submitted an edit that improves the code so it's easier to read. – Konstantin Dec 10 '12 at 01:30
  • Any reason not to use ordinal() for the index and a for each loop, like: for (State state: State.values() { names[state.ordinal()] = state.toString(); } – cosimo193 Jan 19 '17 at 18:01
  • Shouldn't it be `State[] states = State.values();` – nedlud May 11 '18 at 04:17
  • @PermGenError, I would like to know how to return the values (English, L1) , L1 being the value; after comparing the arrays of string with the Enums arrays. For example, the String Arrays contains English, etc etc, but I want to return a list of L1, L2 etc if it matches the ones in the Enums. – Karen Goh Aug 19 '18 at 11:02
23

If you can use Java 8, this works nicely (alternative to Yura's suggestion, more efficient):

public static String[] names() {
    return Stream.of(State.values()).map(State::name).toArray(String[]::new);
}
Kris Boyd
  • 798
  • 10
  • 17
19

Here`s an elegant solution using Apache Commons Lang 3:

EnumUtils.getEnumList(State.class)

Although it returns a List, you can convert the list easily with list.toArray()

informatik01
  • 16,038
  • 10
  • 74
  • 104
Sergio Trapiello
  • 718
  • 9
  • 18
  • 7
    `EnumUtils.getEnumList(enumClass)` returns the enum values, not the Strings. You could use `EnumUtils.getEnumMap(enumClass).keySet()`, but the order might be different. – Dan Halbert Nov 01 '16 at 15:47
12

With java 8:

Arrays.stream(MyEnum.values()).map(Enum::name)
                    .collect(Collectors.toList()).toArray();
Yura Galavay
  • 426
  • 6
  • 10
  • 2
    While it probably works, this implementation is quite inefficient, first creating an ArrayList, adding all elements, then creating an array and copying everything again. – Daniel Bimschas Mar 09 '15 at 13:03
  • Any time soon "everyone" will be using streams to accomplish the most basic operations... and that is not a very good idea. – marcolopes Apr 07 '15 at 05:07
  • considering the fact that the number of elements in enums is usually rather small, I think that Yura's solution will be fine for many use cases. Naturally, it will depend on the specific situation... – stefan.m Jan 12 '17 at 17:10
6

I would write it like this

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()]);
}
Raymond Chenon
  • 11,482
  • 15
  • 77
  • 110
4

Another ways :

First one

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

Other way

Stream.of(FieldType.values()).map(f -> f.toString()).toArray(String[]::new);
Durgpal Singh
  • 11,481
  • 4
  • 37
  • 49
  • 2
    In *this* case `toString()` works, but in the general case it does not, because `toString()` can be be overridden. Use `.name()` to reliably get the instance *name* as a String. – Bohemian Nov 20 '17 at 03:01
3

Something like this would do:

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

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

  return names;
}

The documentation recommends using toString() instead of name() in most cases, but you have explicitly asked for the name here.

David Webb
  • 190,537
  • 57
  • 313
  • 299
  • 1
    Although it doesn't particularly matter, a regular for loop offers better performance than a foreach loop in this situation. Plus, `values()` is called twice when it need only be called once. – FThompson Dec 09 '12 at 00:26
  • 1
    @Vulcan I think performance would only be an issue with this if it were run hundreds of thousands of times. Besides, `values()` is a method generated by the compiler, so I'm guessing it's pretty optimized. Finally, I remember reading somewhere that for-each loops are more efficient than standard, incremental for loops, but then again — [it just doesn't matter](http://www.codinghorror.com/blog/2005/01/micro-optimization-and-meatballs.html). – Konstantin Dec 09 '12 at 01:01
  • @Konstantin considering that the foreach loop in java is implemented with a standard for loop, where ever you read that foreach loops are ever more efficient is incorrect. – sage88 Nov 22 '14 at 19:23
  • 1
    @sage88 I was referring to for loops in which you retrieve elements using a numeric index, which you increment in each cycle. For example: `for (int i = 0; i < a.length; i++) /* do stuff */;` In this case, for-each loops _are_, in fact, more efficient. A quick SO search on the matter gives us this: http://stackoverflow.com/questions/2113216/which-is-more-efficient-a-for-each-loop-or-an-iterator – Konstantin Nov 24 '14 at 03:15
  • @Konstantin Any time you have a data structure that allows random access, as is the case with enum values, which returns an array, a C-style for loop is faster than using a for each loop. The for each loop has to generate an iterator, which makes it slower. The link you posted gives an example of using a standard for loop on a linked list using get(i), which is of course worse. When using a non-random access data structure the for each loop is faster, but on arrays it has a greater overhead. Also, since it's a primitive array, not an ArrayList, there's no performance hit from .size(). – sage88 Nov 24 '14 at 07:22
  • Though I should say that I was wrong above, for each does't use a standard for loop, it uses an iterator. – sage88 Nov 24 '14 at 07:22
3

Got the simple solution

Arrays.stream(State.values()).map(Enum::name).collect(Collectors.toList())
Pritish Joshi
  • 2,025
  • 3
  • 18
  • 33
2

i'd do it this way (but i'd probably make names an unmodifiable set instead of an array):

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));
    }
}
Ray Tayek
  • 9,841
  • 8
  • 50
  • 90
  • I'd do something like this as well if I needed to repeatedly get the enum names, but since the `names()` method is only called sparingly, I think generating an array on the spot is fine. – Konstantin Dec 09 '12 at 01:16
2

My solution, with manipulation of strings (not the fastest, but is compact):

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(",");
    }
}
ceklock
  • 6,143
  • 10
  • 56
  • 78
2

the ordinary way (pun intended):

String[] myStringArray=new String[EMyEnum.values().length];
for(EMyEnum e:EMyEnum.values())myStringArray[e.ordinal()]=e.toString();
Aquarius Power
  • 3,729
  • 5
  • 32
  • 67
1

I have the same need and use a generic method (inside an ArrayUtils class):

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

And just define a STATIC inside the enum...

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

Java enums really miss a names() and get(index) methods, they are really helpful.

marcolopes
  • 9,232
  • 14
  • 54
  • 65
1

org.apache.commons.lang3.EnumUtils.getEnumMap(State.class).keySet()

wutzebaer
  • 14,365
  • 19
  • 99
  • 170
1

I did a bit test on @Bohemian's solution. The performance is better when using naive loop instead.

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);
}
Chuck
  • 76
  • 6
  • You should give the statistics about performance, then people can judge for themselves if the performance loss is significant or not. I suppose that most people will not have 100+ or 1000+ values for an Enum. – Rauni Lillemets Aug 09 '18 at 07:43
1

Very similar to the accepted answer, but since I learnt about EnumSet, I can't help but use it everywhere. So for a tiny bit more succinct (Java8) answer:

public static String[] getNames(Class<? extends Enum<?>> e) {
  return EnumSet.allOf(e).stream().map(Enum::name).toArray(String[]::new);
}
Rhubarb
  • 34,705
  • 2
  • 49
  • 38
1

You can get Enum String value by "Enum::name"

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

This implementation does not require additional "function" and "field". Just add this function to get the result you want.

leeJB
  • 1,395
  • 6
  • 13
1

Basing off from Bohemian's answer for Kotlin:

Use replace() instead of replaceAll().

Arrays.toString(MyEnum.values()).replace(Regex("^.|.$"), "").split(", ").toTypedArray()

Side note: Convert to .toTypedArray() for use in AlertDialog's setSingleChoiceItems, for example.

0

If you want the shortest you can try

public static String[] names() {
    String test = Arrays.toString(values());
    return text.substring(1, text.length()-1).split(", ");
}
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
0

Just a thought: maybe you don't need to create a method to return the values of the enum as an array of strings.

Why do you need the array of strings? Maybe you only need to convert the values when you use them, if you ever need to do that.

Examples:

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()));
ceklock
  • 6,143
  • 10
  • 56
  • 78
0

Try this:

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;
}
Samuel Philipp
  • 10,631
  • 12
  • 36
  • 56
0

Another way to do it in Java 7 or earlier would be to use Guava:

public static String[] names() {
    return FluentIterable.from(values()).transform(Enum::name).toArray(String.class);
}
Justin Lee
  • 76
  • 1
  • 3
0

You can put enum values to list of strings and convert to array:

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

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

    String[] stateArray = new String[stateList.size()];
    stateArray = stateList.toArray(stateArray);
Veljko P.
  • 89
  • 5
0

The easiest way:

Category[] category = Category.values();
for (int i = 0; i < cat.length; i++) {
     System.out.println(i  + " - " + category[i]);
}

Where Category is Enum name

Ilja Tarasovs
  • 181
  • 2
  • 13
0
enum CardType {
    CLUB, DIAMOND, HEART, SPADE;

}

public class Control {
    public static void main(String[] args) {

        String[] cardsArray = new String[CardType.values().length];
        int i = 0;

        for (CardType cardType : CardType.values()){
            cardsArray[i] = cardType.name();
            i++;
        }
        //to output the array
        for (int j = 0; j < CardType.values().length; j++){
            System.out.println(cardsArray[j]);
        }
    }
}
Syscall
  • 19,327
  • 10
  • 37
  • 52
  • Create a new String array. You can then populate it with values() from your enum by using the enhanced for-loop to loop through the enum. – EngNjuguna Apr 01 '21 at 04:31
0

You don't need to use the Streams API or the Apache Commons library. Here is arguably the simplest and the fastest way to do this:

public static String[] names() {
    String[] names = new String[State.values().length];
    State[] values = State.values();
    for (int i = 0, valuesLength = values.length; i < valuesLength; i++) {
        names[i] = values[i].toString();
    }
    return names;
}
bezbos.
  • 1,551
  • 2
  • 18
  • 33