Làm cách nào để lấy Giá trị Enum từ chỉ mục trong Java?


96

Tôi có một enum trong Java:

public enum Months
{
    JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC
}

Tôi muốn truy cập các giá trị enum theo chỉ mục, ví dụ:

Months(1) = JAN;
Months(2) = FEB;
...

Tôi sẽ làm điều đó như thế nào?


12
Trong khoa học máy tính, chỉ số bắt đầu từ 0, không phải 1 ;-)
fredoverflow

1
Bạn có chắc chắn muốn? Nói chung, bạn không nên chạm vào thứ tự, ngoài việc triển khai các cấu trúc dữ liệu cấp thấp (và sau đó, sử dụng các cơ chế thay thế, chẳng hạn như tên, để duy trì sự bền bỉ).
Tom Hawtin - tackline

Bạn cũng có thể sử dụng các hằng số trong lớp java.util.Calendar. Chúng được đánh số từ 0 - 11 từ tháng 1 đến tháng 12. Hãy cẩn thận với số 12 vì đó là UnDecember (điều gì đó liên quan đến âm lịch). Nhưng tôi chỉ tò mò tại sao lại phát minh ra hằng số bánh xe tháng mà đã có sẵn trong JRE?
Chris Aldrich

2FredOverflow: Aggree, tôi đã sử dụng lập chỉ mục sai. 2Tom Hawtin: Vâng, tôi chắc chắn. Tôi duy trì dữ liệu với một số khuôn khổ và tôi nhận lại chỉ mục số nguyên, không phải enum. 2Chris Aldrich: Đây chỉ là ví dụ giả không khớp với trường hợp thực.
jk_

Nhân tiện, Java 8 trở lên đi kèm với một Monthenum tích hợp sẵn.
Basil Bourque

Câu trả lời:


229

Thử cái này

Months.values()[index]

37
Lưu ý rằng điều đó sẽ sao chép một bản sao của mảng giá trị mỗi lần, vì vậy nếu bạn đang gọi điều này trong vòng lặp bên trong của mã nhạy cảm về hiệu suất, bạn có thể muốn tạo một bản sao tĩnh và sử dụng nó.
Christopher Barber

1
Tôi bối rối, vậy tại sao tôi không muốn sử dụng một mảng thay thế?
Anudeep Samaiya

@AnudeepSamaiya có thể chúng ta muốn sử dụng hằng số enum thích hợp (Months.JAN) trong mã thay vì tháng [1] ở mọi nơi.
Harry Joy

@Christopher Barber đây là một lớp lót cho "thực hiện một bản sao tĩnh": public static final ArrayList<Months> ALL = new ArrayList<Month>() {{ for (Months m : Months.values()) add(m); }};, sau đó bạn có thể truy cập vào các yếu tố vớiMonths i = ALL.get(index)
muelleth

Sẽ dễ dàng hơn để chỉ cần sử dụng Months.values () clone () hoặc nếu bạn đang hoang tưởng về mutability để bọc nó trong một danh sách bất biến (xem bộ sưu tập).
Christopher Barber

20

Đây là ba cách để làm điều đó.

public enum Months {
    JAN(1), FEB(2), MAR(3), APR(4), MAY(5), JUN(6), JUL(7), AUG(8), SEP(9), OCT(10), NOV(11), DEC(12);


    int monthOrdinal = 0;

    Months(int ord) {
        this.monthOrdinal = ord;
    }

    public static Months byOrdinal2ndWay(int ord) {
        return Months.values()[ord-1]; // less safe
    }

    public static Months byOrdinal(int ord) {
        for (Months m : Months.values()) {
            if (m.monthOrdinal == ord) {
                return m;
            }
        }
        return null;
    }
    public static Months[] MONTHS_INDEXED = new Months[] { null, JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC };

}




import static junit.framework.Assert.assertEquals;

import org.junit.Test;

public class MonthsTest {

@Test
public void test_indexed_access() {
    assertEquals(Months.MONTHS_INDEXED[1], Months.JAN);
    assertEquals(Months.MONTHS_INDEXED[2], Months.FEB);

    assertEquals(Months.byOrdinal(1), Months.JAN);
    assertEquals(Months.byOrdinal(2), Months.FEB);


    assertEquals(Months.byOrdinal2ndWay(1), Months.JAN);
    assertEquals(Months.byOrdinal2ndWay(2), Months.FEB);
}

}

5
public staticcó thể thay đổi (cả mảng và không final). Euw. Và một IllegalArgumentExceptionsẽ có ý nghĩa hơn nhiều so với việc trả lại một nullquả bom.
Tom Hawtin - tackline vào

2

Tôi chỉ thử tương tự và đưa ra giải pháp sau:

public enum Countries {
    TEXAS,
    FLORIDA,
    OKLAHOMA,
    KENTUCKY;

    private static Countries[] list = Countries.values();

    public static Countries getCountry(int i) {
        return list[i];
    }

    public static int listGetLastIndex() {
        return list.length - 1;
    }
}

Lớp có các giá trị của riêng nó được lưu bên trong một mảng và tôi sử dụng mảng để lấy enum tại vị trí chỉ mục. Như đã đề cập ở trên, các mảng bắt đầu được đếm từ 0, nếu bạn muốn chỉ mục của mình bắt đầu từ '1', chỉ cần thay đổi hai phương thức sau thành:

public static String getCountry(int i) {
    return list[(i - 1)];
}

public static int listGetLastIndex() {
    return list.length;
}

Bên trong Main của tôi, tôi nhận được các quốc gia-đối tượng cần thiết với

public static void main(String[] args) {
   int i = Countries.listGetLastIndex();
   Countries currCountry = Countries.getCountry(i);
}

đặt currCountry thành quốc gia cuối cùng, trong trường hợp này là Countries.KENTUCKY.

Chỉ cần nhớ rằng mã này bị ảnh hưởng rất nhiều bởi ArrayOutOfBoundsExceptions nếu bạn đang sử dụng các chỉ báo mã cứng để lấy các đối tượng của mình.


1

Gần đây tôi đã gặp vấn đề tương tự và sử dụng giải pháp do Harry Joy cung cấp. Tuy nhiên, giải pháp đó chỉ hoạt động với sự phân tách dựa trên 0. Tôi cũng sẽ không coi nó là lưu vì nó không xử lý các chỉ mục nằm ngoài phạm vi.

Giải pháp mà tôi đã kết thúc sử dụng có thể không đơn giản nhưng nó hoàn toàn tiết kiệm và sẽ không làm ảnh hưởng đến hiệu suất của mã của bạn ngay cả với các enum lớn:

public enum Example {

    UNKNOWN(0, "unknown"), ENUM1(1, "enum1"), ENUM2(2, "enum2"), ENUM3(3, "enum3");

    private static HashMap<Integer, Example> enumById = new HashMap<>();
    static {
        Arrays.stream(values()).forEach(e -> enumById.put(e.getId(), e));
    }

    public static Example getById(int id) {
        return enumById.getOrDefault(id, UNKNOWN);
    }

    private int id;
    private String description;

    private Example(int id, String description) {
        this.id = id;
        this.description= description;
    }

    public String getDescription() {
        return description;
    }

    public int getId() {
        return id;
    }
}

Nếu bạn chắc chắn rằng bạn sẽ không bao giờ nằm ​​ngoài phạm vi với chỉ mục của mình và bạn không muốn sử dụng UNKNOWNnhư tôi đã làm ở trên, tất nhiên bạn cũng có thể làm:

public static Example getById(int id) {
        return enumById.get(id);
}
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.