Bir numaralandırmadaki tüm isimleri String olarak alma []


97

Enum öğelerinin adlarını bir dizi Strings olarak almanın en kolay ve / veya en kısa yolu nedir?

Bununla kastettiğim, örneğin, aşağıdaki numaralandırmam varsa şudur:

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

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

names()yöntem, bir dizi dönmek { "NEW", "RUNNABLE", "BLOCKED", "WAITING", "TIMED_WAITING", "TERMINATED" }.


2
Neden tam olarak benim dışımda olduğunu yapan yerel bir Enum yöntemi yok ... ve ayrıca değeri elde
etmeyi

Yanıtlar:


92

İşte herhangi bir enumsınıf için tek satır :

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

Pre Java 8, daha az zarif olsa da hala tek satırlık bir programdır:

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

Böyle arayacaksın:

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

Sabit kodlu bir enum sınıfı için basit bir şey istiyorsanız:

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

2
İşi yapmanın en hızlı yolu değil, güzel bir normal ifade.
ceklock

2
Java 8 çözümünde, yöntem kapsamı dışında, e.getEnumConstants()sizin yerine kullanabilirsinizYourEnumName.values()
Eido95

1
@ Eido95 YourEnumName.values(), sınıf üzerinde herhangi bir enum için yeniden kullanılamayan statik bir yöntemi çağırıyor . Herhangi bir enum sınıfı getEnumConstants()için eserler kullanma . Bu yöntemdeki fikir, cevabın son satırı gibi arayabileceğiniz bir yardımcı yöntem oluşturmaktır.
Bohemian

numaranız için özel bir etiket istiyorsanız, sıralama sınıfınızda toString () öğesini geçersiz kılın.
ralphgabb

Lütfen açıklar Class<? extends Enum<?>> emısın?
Carmageddon

63

String[]Adlar için bir dizi oluşturun ve values()tüm enum değerlerini döndüren statik yöntemi çağırın , ardından değerler üzerinde yineleyin ve ad dizisini doldurun.

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()Diziyi yerel bir değişkende önbelleğe almak yerine neden 13 kez çağırıp her seferinde yeni bir dizi oluşturalım? Neden yerine geçersiz kılınabilen toString () kullanılıyor name()?
JB Nizet

@JBNizet heheh, aslında bunu IDE'mde denedim ve bir Durum dizisi oluşturmak için tembellik ettim sanırım, hehe, yine de şimdi
düzenledim

2
Hala isimleri değil, toString () değerlerini döndürüyorsunuz.
JB Nizet

@JBNizet hmm, tbh, name()şimdiye kadar bir yöntem olduğunu gerçekten bilmiyorum . ne kadar aptalım: Bana haber verdiğin için teşekkürler :)
PermGenError

1
Bu yanıtı kabul ettim, ancak daha kolay okunabilmesi için kodu iyileştiren bir düzenleme gönderdim.
Konstantin

15

İşte Apache Commons Lang 3'ü kullanan zarif bir çözüm :

EnumUtils.getEnumList(State.class)

Bir Liste döndürmesine rağmen, listeyi kolayca dönüştürebilirsiniz. list.toArray()


6
EnumUtils.getEnumList(enumClass)Dizeleri değil, enum değerlerini döndürür. Kullanabilirsin EnumUtils.getEnumMap(enumClass).keySet(), ama sıra farklı olabilir.
Dan Halbert

13

Java 8'i kullanabiliyorsanız, bu iyi çalışır (Yura'nın önerisine alternatif, daha verimli):

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

9

Java 8 ile:

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

2
Muhtemelen çalışsa da, bu uygulama oldukça verimsizdir, önce bir ArrayList oluşturmak, tüm öğeleri eklemek, sonra bir dizi oluşturmak ve her şeyi yeniden kopyalamak.
Daniel Bimschas

Yakında "herkes" en temel işlemleri gerçekleştirmek için akışları kullanıyor olacak ... ve bu pek de iyi bir fikir değil.
marcolopes

Numaralandırmalardaki eleman sayısının genellikle oldukça az olduğu gerçeğini göz önünde bulundurarak, Yura'nın çözümünün birçok kullanım durumu için iyi olacağını düşünüyorum. Doğal olarak, özel duruma bağlı olacaktır ...
stefan.m

6

Böyle yazardım

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

Başka yollar:

Birincisi

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

Diğer yol

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

2
Gelen bu durumda toString()çalışır, ancak çünkü genel durumda Götürmezse, toString()geçersiz kılınan olabilir edilebilir. .name()Örnek adını bir String olarak güvenilir şekilde almak için kullanın .
Bohemian

3

Bunun gibi bir şey yapardı:

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

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

  return names;
}

Belgeler çoğu durumda toString()yerine kullanmanızı önerirname() , ancak siz açıkça burada adı istediniz.


1
Özellikle önemli olmasa da, bu durumda normal bir for döngüsü, foreach döngüsünden daha iyi performans sunar. Ayrıca, values()yalnızca bir kez aranması gerektiğinde iki kez aranır.
FThompson

1
@Vulcan Bence performans sadece yüzbinlerce kez çalıştırılsaydı bununla ilgili bir sorun olurdu. Ayrıca, values()derleyici tarafından oluşturulan bir yöntemdir, bu yüzden oldukça optimize edilmiş olduğunu tahmin ediyorum. Son olarak, her döngü için standarttan daha verimli, döngüler için artımlı olduğunu bir yerde okuduğumu hatırlıyorum, ancak yine de önemli değil .
Konstantin

@Konstantin, java'daki foreach döngüsünün bir for döngüsü ile uygulandığını düşünürse, foreach döngülerinin her zamankinden daha verimli olduğunu okuduğunuzda yanlıştır.
sage88

1
@ sage88 Öğeleri sayısal bir indeks kullanarak aldığınız ve her döngüde artırdığınız döngülerden bahsediyordum. Örneğin: for (int i = 0; i < a.length; i++) /* do stuff */;Bu durumda, her döngü için aslında daha verimlidir. Konuyla ilgili hızlı bir SO araştırması bize şunu verir: stackoverflow.com/questions/2113216/…
Konstantin

@Konstantin Bir dizi döndüren enum değerlerinde olduğu gibi, rasgele erişime izin veren bir veri yapınız olduğunda, C-stili for döngüsü, her döngü için a kullanmaktan daha hızlıdır. Her döngü için bir yineleyici oluşturması gerekir, bu da onu daha yavaş yapar. Gönderdiğiniz bağlantı, bağlı bir listede get (i) kullanarak bir standart for döngüsü kullanmaya bir örnek verir ki bu elbette daha kötüdür. Rasgele erişimli olmayan bir veri yapısı kullanıldığında, her döngü için daha hızlıdır, ancak dizilerde daha büyük bir ek yüke sahiptir. Ayrıca, bir ArrayList değil, ilkel bir dizi olduğu için, .size () 'den performans vuruşu yoktur.
sage88

2

Dizelerin manipülasyonu ile çözümüm (en hızlı değil, kompakt):

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(",");
    }
}

ve java7 uyumlu!
Aquarius Power

2

sıradan yol (amaçlanan):

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

1

bu şekilde yapardım (ama isimleri muhtemelen bir dizi yerine değiştirilemez bir küme yapardım):

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

Enum adlarını tekrar tekrar almam gerekirse, buna benzer bir şey de yapardım, ancak names()yöntem yalnızca idareli çağrıldığı için, yerinde bir dizi oluşturmanın iyi olduğunu düşünüyorum.
Konstantin

1

Aynı ihtiyacım var ve genel bir yöntem kullanıyorum (ArrayUtils sınıfının içinde):

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

Ve sadece numaralandırma içinde bir STATİK tanımlayın ...

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

Java numaralandırmaları bir adları () ve get (dizin) yöntemlerini gerçekten özlüyorlar, gerçekten faydalıdırlar.


1

@ Bohemian'ın çözümü üzerinde biraz test yaptım. Bunun yerine naif döngü kullanıldığında performans daha iyidir.

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

Performansla ilgili istatistikleri vermelisiniz, o zaman insanlar performans kaybının önemli olup olmadığını kendileri yargılayabilirler. Sanırım çoğu insan bir Enum için 100+ veya 1000+ değere sahip olmayacak.
Rauni Lillemets


1

Kabul edilen cevaba çok benziyor, ancak EnumSet'i öğrendiğimden beri, yardım edemem ama her yerde kullanıyorum. Yani biraz daha kısa (Java8) cevap için:

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

0

En kısasını istiyorsan deneyebilirsin

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

En kısa değil :) Tek satırlık vales()bir cevap için cevabımı görün (hala yalnızca bir kez çağrılır )
Bohemian

0

Sadece bir düşünce: belki de enum değerlerini bir dizi dizisi olarak döndürmek için bir yöntem oluşturmanız gerekmez.

Dize dizisine neden ihtiyacınız var? Belki de, bunu yapmanız gerektiğinde, yalnızca onları kullandığınızda dönüştürmeniz gerekir.

Örnekler:

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 veya önceki sürümlerde bunu yapmanın başka bir yolu da Guava kullanmaktır:

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

0

Bunu dene:

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

Enum değerlerini dizeler listesine koyabilir ve diziye dönüştürebilirsiniz:

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

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

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

0

En kolay yol:

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

Kategori Enumadı nerede

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.