Nhận tất cả các tên trong enum dưới dạng chuỗi []


95

Cách dễ nhất và / hoặc ngắn nhất có thể để lấy tên của các phần tử enum dưới dạng một mảng Strings là gì?

Ý tôi muốn nói ở đây là nếu, ví dụ, tôi có enum sau:

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

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

các names()phương pháp sẽ trở lại mảng { "NEW", "RUNNABLE", "BLOCKED", "WAITING", "TIMED_WAITING", "TERMINATED" }.


2
Tại sao không có một phương pháp có nguồn gốc Enum thực hiện chính xác rằng đó là ngoài tôi ... và cũng là một get (index) để đơn giản hóa get của giá trị ()
marcolopes

Câu trả lời:


91

Đây là một lớp lót cho bất kỳ enumlớp nào :

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

Pre Java 8 vẫn là một lớp lót, mặc dù kém thanh lịch hơn:

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

Cái mà bạn sẽ gọi như thế này:

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

Nếu bạn chỉ muốn một cái gì đó đơn giản cho một lớp enum được mã hóa cứng:

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

2
Không phải là cách nhanh nhất để thực hiện công việc, nhưng regex tốt.
ceklock

2
Trong Java giải pháp 8, bên ngoài một phạm vi phương pháp, thay vì e.getEnumConstants()bạn có thể sử dụngYourEnumName.values()
Eido95

1
@ Eido95 YourEnumName.values()đang sử dụng đang gọi một phương thức tĩnh trên lớp, phương thức này không thể được sử dụng lại cho bất kỳ enum nào . Sử dụng getEnumConstants()hoạt động cho bất kỳ lớp enum nào . Ý tưởng với phương pháp này là tạo lại một phương thức tiện ích mà bạn có thể gọi như dòng cuối cùng của câu trả lời.
Bohemian

nếu bạn muốn có một nhãn tùy chỉnh cho enum của mình, hãy ghi đè toString () trong lớp enum của bạn.
ralphgabb

Bạn có thể vui lòng giải thích Class<? extends Enum<?>> e?
Carmageddon

63

Tạo một String[]mảng cho các tên và gọi values()phương thức tĩnh trả về tất cả các giá trị enum, sau đó lặp qua các giá trị và điền vào mảng tên.

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
Tại sao gọi values()13 lần, tạo một mảng mới mỗi lần, thay vì lưu mảng trong một biến cục bộ? Tại sao lại sử dụng toString (), có thể ghi đè thay vì name()?
JB Nizet 9/12/12

@JBNizet heheh, tôi thực sự cố gắng này trong IDE và cách của tôi để lười biếng để tạo ra một mảng State tôi đoán, hehe, dù sao iedited nó bây giờ :)
PermGenError

2
Bạn vẫn không trả về các tên, nhưng các giá trị toString ().
JB Nizet 9/12/12

@JBNizet hmm, tbh, tôi không thực sự biết rằng có một name()phương pháp cho đến bây giờ. cách ngu ngốc của tôi: P cảm ơn vì đã cho tôi biết :)
PermGenError

1
Tôi đã chấp nhận câu trả lời này, nhưng tôi đã gửi một bản chỉnh sửa để cải thiện mã để dễ đọc hơn.
Konstantin

14

Đây là một giải pháp thanh lịch sử dụng Apache Commons Lang 3 :

EnumUtils.getEnumList(State.class)

Mặc dù nó trả về một Danh sách, bạn có thể chuyển đổi danh sách dễ dàng với list.toArray()


5
EnumUtils.getEnumList(enumClass)trả về các giá trị enum, không trả về các Chuỗi. Bạn có thể sử dụng EnumUtils.getEnumMap(enumClass).keySet(), nhưng thứ tự có thể khác.
Dan Halbert

11

Nếu bạn có thể sử dụng Java 8, điều này hoạt động tốt (thay thế cho đề xuất của Yura, hiệu quả hơn):

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

9

Với java 8:

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

2
Mặc dù nó có thể hoạt động, nhưng việc triển khai này khá kém hiệu quả, đầu tiên là tạo ArrayList, thêm tất cả các phần tử, sau đó tạo một mảng và sao chép lại mọi thứ.
Daniel Bimschas

Bất cứ lúc nào "mọi người" sẽ sớm sử dụng các luồng để hoàn thành các hoạt động cơ bản nhất ... và đó không phải là một ý tưởng hay.
marcolopes

xem xét thực tế là số lượng phần tử trong enums thường khá ít, tôi nghĩ rằng giải pháp của Yura sẽ ổn cho nhiều trường hợp sử dụng. Đương nhiên, nó sẽ phụ thuộc vào tình hình cụ thể ...
stefan.m

6

Tôi sẽ viết nó như thế này

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

Một cái gì đó như thế này sẽ làm:

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

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

  return names;
}

Tài liệu khuyến nghị sử dụng toString()thay vì name()trong hầu hết các trường hợp , nhưng bạn đã yêu cầu rõ ràng tên ở đây.


1
Mặc dù điều đó không đặc biệt quan trọng, nhưng vòng lặp for thông thường cung cấp hiệu suất tốt hơn vòng lặp foreach trong tình huống này. Thêm vào đó, values()được gọi hai lần khi nó chỉ cần được gọi một lần.
FThompson 09/12/12

1
@Vulcan Tôi nghĩ rằng hiệu suất sẽ chỉ là một vấn đề với điều này nếu nó được chạy hàng trăm nghìn lần. Bên cạnh đó, values()là một phương thức được tạo bởi trình biên dịch, vì vậy tôi đoán nó được tối ưu hóa khá tốt. Cuối cùng, tôi nhớ đã đọc ở đâu đó rằng mỗi vòng lặp hiệu quả hơn so với tiêu chuẩn, tăng dần cho các vòng lặp, nhưng sau đó một lần nữa - điều đó không quan trọng .
Konstantin

@Konstantin cho rằng vòng lặp foreach trong java được triển khai với vòng lặp for chuẩn, trong đó bạn đọc rằng vòng lặp foreach hiệu quả hơn bao giờ hết là không chính xác.
sage88

1
@ sage88 Tôi đang đề cập đến các vòng lặp trong đó bạn truy xuất các phần tử bằng cách sử dụng chỉ mục số, bạn tăng dần trong mỗi chu kỳ. Ví dụ: for (int i = 0; i < a.length; i++) /* do stuff */;Trong trường hợp này , trên thực tế, đối với mỗi vòng lặp hiệu quả hơn. Một tìm kiếm SO nhanh chóng về vấn đề này cung cấp cho chúng tôi điều này: stackoverflow.com/questions/2113216/…
Konstantin

@Konstantin Bất kỳ khi nào bạn có cấu trúc dữ liệu cho phép truy cập ngẫu nhiên, như trường hợp với các giá trị enum, trả về một mảng, vòng lặp for kiểu C sẽ nhanh hơn so với việc sử dụng một cho mỗi vòng lặp. Đối với mỗi vòng lặp phải tạo một trình lặp, điều này làm cho nó chậm hơn. Liên kết bạn đã đăng đưa ra một ví dụ về việc sử dụng vòng lặp tiêu chuẩn cho danh sách được liên kết bằng cách sử dụng get (i), điều này tất nhiên là tệ hơn. Khi sử dụng cấu trúc dữ liệu truy cập không ngẫu nhiên, cho mỗi vòng lặp nhanh hơn, nhưng trên các mảng, nó có chi phí lớn hơn. Ngoài ra, vì nó là một mảng nguyên thủy, không phải ArrayList, nên không có hiệu suất nào từ .size ().
sage88

3

Các cách khác:

Đầu tiên

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

Cách khác

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

1
Trong này trường hợp toString()hoạt động, nhưng trong trường hợp tổng quát nó không, vì toString()có thể được ghi đè. Sử dụng .name()để lấy tên cá thể một cách đáng tin cậy dưới dạng Chuỗi.
Bohemian

2

Giải pháp của tôi, với thao tác trên chuỗi (không phải là nhanh nhất, nhưng nhỏ gọn):

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

và tuân thủ java7!
Aquarius Power

1

tôi sẽ làm theo cách này (nhưng có lẽ tôi sẽ đặt tên thành một tập hợp không thể thay đổi thay vì một mảng):

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

Tôi cũng sẽ làm điều gì đó như thế này nếu tôi cần liên tục lấy các tên enum, nhưng vì names()phương thức này chỉ được gọi một cách ít ỏi, tôi nghĩ rằng việc tạo một mảng tại chỗ là tốt.
Konstantin

1

Tôi có cùng nhu cầu và sử dụng một phương thức chung (bên trong một lớp 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;
}

Và chỉ cần xác định một STATIC bên trong enum ...

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

Các enums trong Java thực sự bỏ sót các phương thức names () và get (index), chúng thực sự hữu ích.


1

theo cách thông thường (ý định chơi chữ):

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

1

Tôi đã thực hiện một thử nghiệm nhỏ về giải pháp của @ Bohemian. Hiệu suất tốt hơn khi sử dụng vòng lặp ngây thơ.

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

Bạn nên đưa ra các số liệu thống kê về hiệu suất, sau đó mọi người có thể tự đánh giá xem việc giảm hiệu suất có đáng kể hay không. Tôi cho rằng hầu hết mọi người sẽ không có hơn 100 hoặc hơn 1000 giá trị cho một Enum.
Rauni Lillemets


0

Nếu bạn muốn ngắn nhất, bạn có thể thử

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

Không phải là ngắn nhất :) Xem câu trả lời của tôi cho một chữ lót (vẫn chỉ gọi vales()một lần)
Bohemian

0

Chỉ cần một suy nghĩ: có thể bạn không cần tạo một phương thức để trả về các giá trị của enum dưới dạng một mảng chuỗi.

Tại sao bạn cần mảng chuỗi? Có thể bạn chỉ cần chuyển đổi các giá trị khi bạn sử dụng chúng, nếu bạn cần làm điều đó.

Ví dụ:

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

Một cách khác để làm điều đó trong Java 7 hoặc phiên bản cũ hơn là sử dụng Guava:

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

0

Thử cái này:

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

Bạn có thể đặt các giá trị enum vào danh sách các chuỗi và chuyển đổi thành mảng:

    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

Cách dễ nhất:

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

Trong đó Danh mục là Enumtên

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.