Mendapatkan semua nama dalam enum sebagai String []

96

Apa cara termudah dan / atau sesingkat mungkin untuk mendapatkan nama elemen enum sebagai larik Strings?

Yang saya maksud dengan ini adalah jika, misalnya, saya memiliki enum berikut:

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

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

yang names()metode akan kembali array { "NEW", "RUNNABLE", "BLOCKED", "WAITING", "TIMED_WAITING", "TERMINATED" }.

Konstantin
sumber
2
Mengapa tidak ada metode Enum asli yang melakukan persis seperti itu di luar saya ... dan juga get (indeks) untuk menyederhanakan get of value ()
marcolopes

Jawaban:

92

Berikut satu baris untuk semua enumkelas:

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

Pre Java 8 masih satu baris, meskipun kurang elegan:

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

Bahwa Anda akan menelepon seperti ini:

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

Jika Anda hanya menginginkan sesuatu yang sederhana untuk kelas enum berkode keras:

public static String[] names() {
    return Arrays.toString(State.values()).replaceAll("^.|.$", "").split(", ");
}
Bohemian
sumber
2
Bukan cara tercepat untuk melakukan pekerjaan itu, tapi regex yang bagus.
ceklock
2
Dalam solusi Java 8, di luar cakupan metode, alih-alih e.getEnumConstants()Anda dapat menggunakanYourEnumName.values()
Eido95
1
@ Eido95 menggunakan YourEnumName.values()memanggil metode statis pada kelas, yang tidak dapat digunakan kembali untuk enum apa pun . Menggunakan getEnumConstants()karya untuk semua kelas enum. Ide dengan metode ini adalah untuk membuat kembali metode utilitas yang dapat Anda panggil seperti baris terakhir jawaban.
Bohemian
jika Anda menginginkan label kustom untuk enum Anda, ganti toString () di kelas enum Anda.
ralphgabb
Bisakah Anda menjelaskan Class<? extends Enum<?>> e?
Carmageddon
63

Buat String[]larik untuk nama dan panggil values()metode statis yang mengembalikan semua nilai enum, kemudian ulangi nilai dan isi larik nama.

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;
}
PermGenError
sumber
9
Mengapa memanggil values()13 kali, menghasilkan array baru setiap kali, alih-alih menyimpan array dalam variabel lokal? Mengapa menggunakan toString (), yang dapat diganti, bukan name()?
JB Nizet
@JBNizet heheh, sebenarnya saya coba ini di IDE saya dan cara untuk malas membuat state array saya kira, hehe, lagian iedit sekarang :)
PermGenError
2
Anda masih belum mengembalikan nama, tetapi nilai toString ().
JB Nizet
@JBNizet hmm, tbh, saya benar-benar tidak tahu ada name()metode sampai sekarang. Betapa bodohnya saya: Terima kasih telah memberi tahu saya :)
PermGenError
1
Saya menerima jawaban ini, tetapi saya mengirimkan hasil edit yang meningkatkan kode sehingga lebih mudah dibaca.
Konstantin
14

Berikut solusi elegan menggunakan Apache Commons Lang 3 :

EnumUtils.getEnumList(State.class)

Meskipun mengembalikan Daftar, Anda dapat mengonversi daftar dengan mudah dengan list.toArray()

Sergio Trapiello
sumber
5
EnumUtils.getEnumList(enumClass)mengembalikan nilai enum, bukan String. Anda bisa menggunakan EnumUtils.getEnumMap(enumClass).keySet(), tapi urutannya mungkin berbeda.
Dan Halbert
11

Jika Anda dapat menggunakan Java 8, ini berfungsi dengan baik (alternatif dari saran Yura, lebih efisien):

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

Dengan java 8:

Arrays.stream(MyEnum.values()).map(Enum::name)
                    .collect(Collectors.toList()).toArray();
Yura Galavay
sumber
2
Meskipun mungkin berhasil, implementasi ini cukup tidak efisien, pertama-tama buat ArrayList, tambahkan semua elemen, lalu buat larik dan salin semuanya lagi.
Daniel Bimschas
Dalam waktu dekat, "semua orang" akan menggunakan aliran untuk menyelesaikan operasi paling dasar ... dan itu bukan ide yang bagus.
marcolopes
mengingat fakta bahwa jumlah elemen dalam enum biasanya agak kecil, saya pikir solusi Yura akan baik-baik saja untuk banyak kasus penggunaan. Tentu, itu akan tergantung pada situasi spesifik ...
Stefan.m
6

Saya akan menulisnya seperti ini

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
sumber
3

Sesuatu seperti ini akan dilakukan:

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

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

  return names;
}

Dokumentasi merekomendasikan penggunaan toString()alih-alih name()dalam banyak kasus , tetapi Anda secara eksplisit meminta nama di sini.

Dave Webb
sumber
1
Meskipun tidak terlalu penting, loop for biasa menawarkan kinerja yang lebih baik daripada foreach loop dalam situasi ini. Plus, values()dipanggil dua kali jika hanya perlu dipanggil sekali.
FThompson
1
@Vulcan Saya pikir kinerja hanya akan menjadi masalah dengan ini jika dijalankan ratusan ribu kali. Selain itu, values()adalah metode yang dihasilkan oleh kompiler, jadi saya rasa itu cukup dioptimalkan. Akhirnya, saya ingat pernah membaca bahwa for-each loop lebih efisien daripada standar, incremental untuk loop, tapi sekali lagi - itu tidak masalah .
Konstantin
@Konstantin mengingat bahwa foreach loop di java diimplementasikan dengan standar untuk loop, di mana pun Anda membaca bahwa foreach loop lebih efisien adalah salah.
sage88
1
@ sage88 Saya merujuk ke untuk loop di mana Anda mengambil elemen menggunakan indeks numerik, yang Anda tambahkan dalam setiap siklus. Sebagai contoh: for (int i = 0; i < a.length; i++) /* do stuff */;Dalam kasus ini, untuk-masing loop yang , pada kenyataannya, lebih efisien. Pencarian SO cepat tentang masalah ini memberi kita ini: stackoverflow.com/questions/2113216/…
Konstantin
@Konstantin Setiap kali Anda memiliki struktur data yang memungkinkan akses acak, seperti halnya dengan nilai enum, yang mengembalikan array, loop for gaya-C lebih cepat daripada menggunakan a untuk setiap loop. Untuk setiap loop harus menghasilkan iterator, yang membuatnya lebih lambat. Tautan yang Anda posting memberikan contoh penggunaan loop for standar pada daftar tertaut menggunakan get (i), yang tentu saja lebih buruk. Saat menggunakan struktur data akses non-acak, untuk setiap loop lebih cepat, tetapi pada array memiliki overhead yang lebih besar. Selain itu, karena ini adalah array primitif, bukan ArrayList, tidak ada kinerja yang dicapai dari .size ().
sage88
3

Cara lain:

Pertama

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

Cara lain

Stream.of(FieldType.values()).map(f -> f.toString()).toArray(String[]::new);
Durgpal Singh
sumber
1
Dalam kasus initoString() berhasil, tetapi dalam kasus umum tidak, karena toString()dapat diganti. Gunakan .name()untuk mendapatkan nama instance sebagai String dengan andal .
Bohemian
2

Solusi saya, dengan manipulasi string (bukan yang tercepat, tetapi ringkas):

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
sumber
dan sesuai dengan java7!
Aquarius Power
1

saya akan melakukannya dengan cara ini (tetapi saya mungkin akan membuat nama menjadi set yang tidak dapat dimodifikasi daripada 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
sumber
Saya akan melakukan sesuatu seperti ini juga jika saya perlu berulang kali mendapatkan nama enum, tetapi karena names()metode ini hanya dipanggil dengan hemat, saya pikir membuat array di tempat itu baik-baik saja.
Konstantin
1

Saya memiliki kebutuhan yang sama dan menggunakan metode generik (di dalam kelas 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;
}

Dan cukup tentukan STATIC di dalam enum ...

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

Enum Java benar-benar kehilangan metode names () dan get (index), mereka sangat membantu.

marcolopes
sumber
1

cara biasa (permainan kata-kata):

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

Saya melakukan sedikit tes pada solusi @ Bohemian. Performanya akan lebih baik jika menggunakan naive loop.

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);
}
Membuang
sumber
Anda harus memberikan statistik tentang kinerja, kemudian orang dapat menilai sendiri apakah penurunan kinerja itu signifikan atau tidak. Saya kira kebanyakan orang tidak akan memiliki 100+ atau 1000+ nilai untuk Enum.
Rauni Lillemets
1

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

wutzebaer.dll
sumber
Apa EnumUtils?
Stephan
@wutzebaer downvoting karena soultion ini tidak lengkap - tidak mengembalikan array
Baris
0

Jika Anda ingin yang terpendek, Anda dapat mencoba

public static String[] names() {
    String test = Arrays.toString(values());
    return text.substring(1, text.length()-1).split(", ");
}
Peter Lawrey
sumber
Bukan yang terpendek :) Lihat jawaban saya untuk satu baris (yang masih hanya memanggil vales()sekali)
Bohemian
0

Hanya pemikiran: mungkin Anda tidak perlu membuat metode untuk mengembalikan nilai enum sebagai array string.

Mengapa Anda membutuhkan deretan string? Mungkin Anda hanya perlu mengonversi nilai saat Anda menggunakannya, jika Anda perlu melakukannya.

Contoh:

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
sumber
0

Cara lain untuk melakukannya di Java 7 atau sebelumnya adalah dengan menggunakan Jambu Biji:

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

Coba ini:

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;
}
Matiseli
sumber
0

Anda dapat meletakkan nilai enum ke daftar string dan mengubahnya menjadi 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.
sumber
0

Cara termudah:

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

Dimana Kategori adalah Enumnama

Ilja Tarasovs
sumber