รับชื่อทั้งหมดใน enum เป็น String []


97

อะไรคือวิธีที่ง่ายที่สุดและ / หรือสั้นที่สุดในการตั้งชื่อองค์ประกอบ enum เป็นอาร์เรย์ของStrings

สิ่งที่ฉันหมายถึงก็คือตัวอย่างเช่นถ้าฉันมี enum ต่อไปนี้:

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

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

วิธีการจะกลับอาร์เรย์names(){ "NEW", "RUNNABLE", "BLOCKED", "WAITING", "TIMED_WAITING", "TERMINATED" }


2
เหตุใดจึงไม่มีวิธี Enum ดั้งเดิมที่ทำอย่างนั้นได้อย่างแท้จริงนอกเหนือจากฉัน ... และยังได้รับ (ดัชนี) เพื่อลดความซับซ้อนของการรับค่า ()
marcolopes

คำตอบ:


92

นี่คือซับเดียวสำหรับทุกenumคลาส:

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

Pre 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

หากคุณต้องการอะไรง่ายๆสำหรับคลาส enum แบบฮาร์ดโค้ด:

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

2
ไม่ใช่วิธีที่เร็วที่สุดในการทำงาน แต่ regex ที่ดี
ceklock

2
ในโซลูชัน Java 8 นอกขอบเขตวิธีการแทนคุณe.getEnumConstants()สามารถใช้YourEnumName.values()
Eido95

1
@ Eido95 ใช้YourEnumName.values()กำลังเรียกวิธีการแบบคงที่บนคลาสซึ่งไม่สามารถใช้ซ้ำได้สำหรับenum ใด ๆ การใช้getEnumConstants()งานสำหรับคลาส enum ใด ๆ แนวคิดของวิธีนี้คือการสร้างวิธียูทิลิตี้ขึ้นมาใหม่ซึ่งคุณสามารถเรียกได้เหมือนบรรทัดสุดท้ายของคำตอบ
โบฮีเมียน

หากคุณต้องการป้ายกำกับที่กำหนดเองสำหรับ enum ของคุณให้แทนที่ toString () ในคลาส enum ของคุณ
ralphgabb

คุณช่วยอธิบายได้Class<? extends Enum<?>> eไหม?
Carmageddon

63

สร้างString[]อาร์เรย์สำหรับชื่อและเรียกใช้values()วิธีการแบบคงที่ซึ่งส่งคืนค่า enum ทั้งหมดจากนั้นวนซ้ำค่าและเติมชื่ออาร์เรย์

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 ของฉันและวิธีขี้เกียจสร้างอาร์เรย์สถานะฉันเดาฮิฮิยังไงก็ตามฉันได้แก้ไขแล้ว :)
PermGenError

2
คุณยังไม่คืนชื่อ แต่เป็นค่า toString ()
JB Nizet

@JBNizet อืม tbh ฉันไม่รู้จริงๆว่ามีname()วิธีการจนถึงตอนนี้ ฉันโง่แค่ไหน: P ขอบคุณที่แจ้งให้เราทราบ :)
PermGenError

1
ฉันยอมรับคำตอบนี้ แต่ฉันได้ส่งการแก้ไขที่ปรับปรุงโค้ดเพื่อให้อ่านง่ายขึ้น
Konstantin

15

นี่คือโซลูชันที่สวยงามโดยใช้Apache Commons Lang 3 :

EnumUtils.getEnumList(State.class)

แม้ว่าจะส่งคืนรายการ แต่คุณสามารถแปลงรายการได้อย่างง่ายดายด้วยไฟล์ list.toArray()


6
EnumUtils.getEnumList(enumClass)ส่งคืนค่า enum ไม่ใช่ Strings คุณสามารถใช้ได้EnumUtils.getEnumMap(enumClass).keySet()แต่ลำดับอาจแตกต่างกัน
Dan Halbert

13

หากคุณสามารถใช้ 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

เร็ว ๆ นี้ "ทุกคน" จะใช้สตรีมเพื่อดำเนินการขั้นพื้นฐานให้สำเร็จ ... และนั่นก็ไม่ใช่ความคิดที่ดี
marcolopes

เมื่อพิจารณาถึงความจริงที่ว่าจำนวนองค์ประกอบใน enum มักจะค่อนข้างน้อยฉันคิดว่าโซลูชันของ 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()เพื่อรับชื่ออินสแตนซ์เป็น String ได้อย่างน่าเชื่อถือ
โบฮีเมียน

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
แม้ว่ามันจะไม่สำคัญเป็นพิเศษ แต่การวนซ้ำแบบปกติจะให้ประสิทธิภาพที่ดีกว่า foreach loop ในสถานการณ์นี้ นอกจากvalues()นี้ยังเรียกสองครั้งเมื่อต้องการเรียกเพียงครั้งเดียว
FThompson

1
@ วัลแคนฉันคิดว่าประสิทธิภาพจะเป็นปัญหาหากมีการเรียกใช้หลายแสนครั้ง นอกจากนี้ยังvalues()เป็นวิธีที่สร้างโดยคอมไพเลอร์ดังนั้นฉันเดาว่ามันค่อนข้างเหมาะสม สุดท้ายผมจำได้ว่าเคยอ่านบางที่สำหรับแต่ละลูปมีประสิทธิภาพมากขึ้นกว่ามาตรฐานเพิ่มขึ้นสำหรับลูป แต่แล้วอีกครั้ง - มันก็ไม่ได้เรื่อง
Konstantin

@ Konstantin พิจารณาว่า foreach loop ใน java ถูกนำมาใช้ด้วยมาตรฐานสำหรับ loop ซึ่งคุณเคยอ่านว่า foreach loops มีประสิทธิภาพมากกว่านั้นไม่ถูกต้อง
sage88

1
@ sage88 ฉันหมายถึงลูปที่คุณดึงข้อมูลองค์ประกอบโดยใช้ดัชนีตัวเลขซึ่งคุณจะเพิ่มขึ้นในแต่ละรอบ ตัวอย่างเช่นfor (int i = 0; i < a.length; i++) /* do stuff */;ในกรณีนี้อันที่จริงแล้วสำหรับแต่ละลูปนั้นมีประสิทธิภาพมากกว่า การค้นหา SO อย่างรวดเร็วในเรื่องนี้ทำให้เรามีสิ่งนี้stackoverflow.com/questions/2113216/…
Konstantin

@Konstantin ทุกครั้งที่คุณมีโครงสร้างข้อมูลที่อนุญาตการเข้าถึงแบบสุ่มเช่นเดียวกับกรณีที่มีค่า enum ซึ่งส่งคืนอาร์เรย์สไตล์ C สำหรับลูปจะเร็วกว่าการใช้สำหรับแต่ละลูป สำหรับแต่ละลูปจะต้องสร้างตัววนซ้ำซึ่งทำให้ช้าลง ลิงก์ที่คุณโพสต์ให้ตัวอย่างการใช้มาตรฐานสำหรับการวนซ้ำในรายการที่เชื่อมโยงโดยใช้ get (i) ซึ่งแน่นอนว่าแย่กว่า เมื่อใช้โครงสร้างข้อมูลที่ไม่ใช่การเข้าถึงโดยสุ่มสำหรับแต่ละลูปจะเร็วกว่า แต่ในอาร์เรย์จะมีค่าใช้จ่ายที่มากกว่า นอกจากนี้เนื่องจากเป็นอาร์เรย์ดั้งเดิมไม่ใช่ ArrayList จึงไม่มีประสิทธิภาพที่ได้รับจาก. size ()
sage88

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

ฉันจะทำสิ่งนี้เช่นกันถ้าฉันต้องการรับชื่อ enum ซ้ำ ๆ แต่เนื่องจากnames()เมธอดนี้ถูกเรียกเพียงเท่าที่จำเป็นฉันคิดว่าการสร้างอาร์เรย์ตรงจุดนั้นดี
Konstantin

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 ภายใน enum ...

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

Java enums คิดถึงชื่อ () และรับ (ดัชนี) เมธอดพวกเขามีประโยชน์จริงๆ


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+ หรือ 1,000+ สำหรับ Enum
Rauni Lillemets


1

คล้ายกับคำตอบที่ยอมรับมาก แต่เนื่องจากฉันได้เรียนรู้เกี่ยวกับ EnumSet ฉันก็อดไม่ได้ที่จะใช้มันทุกที่ ดังนั้นสำหรับคำตอบที่สั้นกว่าเล็กน้อย (Java8):

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

0

หากคุณต้องการสั้นที่สุดคุณสามารถลอง

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

ไม่สั้นที่สุด :) ดูคำตอบของฉันสำหรับซับเดียว (ที่ยังเรียกใช้เพียงvales()ครั้งเดียว)
โบฮีเมียน

0

เพียงแค่คิด: บางทีคุณอาจไม่จำเป็นต้องสร้างวิธีการคืนค่าของ enum เป็นอาร์เรย์ของสตริง

ทำไมคุณต้องมีอาร์เรย์ของสตริง? บางทีคุณอาจต้องแปลงค่าเมื่อใช้เท่านั้นหากคุณจำเป็นต้องทำเช่นนั้น

ตัวอย่าง:

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

คุณสามารถใส่ค่า enum ลงในรายการสตริงและแปลงเป็นอาร์เรย์:

    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

วิธีที่ง่ายที่สุด:

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

โดยที่หมวดหมู่คือEnumชื่อ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.