Javaのインデックスから列挙値を取得するにはどうすればよいですか?


96

私はJavaで列挙型を持っています:

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

インデックスで列挙値にアクセスしたい、例えば

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

どうすればよいでしょうか?


12
コンピュータサイエンスでは、インデックスは1ではなく0から始まります;-)
fredoverflow

1
本当によろしいですか?一般に、低レベルのデータ構造を実装する以外に、序数に触れてはなりません(その後、永続化のために名前などの代替メカニズムを使用します)。
トム・ホーティン-タックライン

java.util.Calendarクラスの定数を使用することもできます。1月から12月は0〜11の番号が付けられています。12はUnDecember(太陰暦と関係がある)であるため、注意してください。しかし、JREですでに「ストック」されている月定数のホイールを再発明する理由に興味がありますか?
クリスアルドリッチ

2FredOverflow:同意します。間違ったインデックスを使用しました。2Tom Hawtin:はい、きっと。一部のフレームワークでデータを永続化すると、列挙ではなく整数インデックスが返されます。2Chris Aldrich:これは実際のケースと一致しないダミーの例です。
jk_

ちなみに、Java 8以降にはMonthenumが組み込まれています。
バジルブルク

回答:


229

これを試して

Months.values()[index]

37
は値の配列のコピーを毎回複製することに注意してください。パフォーマンスに敏感なコードの内部ループでこれを呼び出す場合は、静的なコピーを作成してそれを使用することができます。
クリストファーバーバー

1
私は混乱していますが、なぜ代わりに配列を使用したくないのですか?
Anudeep Samaiya 2015

@AnudeepSamaiyaは、コード全体で、months [1]ではなく適切な列挙定数(Months.JAN)を使用したい場合があります。
Harry Joy

@Christopher Barberは、「静的コピーを作成する」ためのワンライナーです:public static final ArrayList<Months> ALL = new ArrayList<Month>() {{ for (Months m : Months.values()) add(m); }};次に、要素にアクセスできますMonths i = ALL.get(index)
muelleth

単純にMonths.values()。clone()を使用する方が簡単です。あるいは、可変性に偏執狂であれば、それを不変リストにラップします(コレクションを参照)
Christopher Barber

20

これを行うには3つの方法があります。

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 static変更可能(配列と非の両方final)。オウ。そしてIllegalArgumentException帰国よりもはるかに理にかなってnull爆弾を。
トム・ホーティン-タックライン

2

私はちょうど同じことを試し、次の解決策を思いつきました:

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

クラスには配列内に保存された独自の値があり、配列を使用してインデックス位置の列挙を取得します。上記のように、配列は0からカウントを開始します。インデックスを「1」から開始する場合は、これらの2つのメソッドを次のように変更するだけです。

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

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

私のメインの中で私は必要な国のオブジェクトを取得します

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

currCountryを最後の国に設定します。この場合は、Countries.KENTUCKYです。

オブジェクトを取得するためにハードコードされたインデックスを使用している場合、このコードはArrayOutOfBoundsExceptionsの影響を非常に強く受けます。


1

最近同じ問題が発生し、Harry Joyが提供するソリューションを使用しました。ただし、このソリューションはゼロベースの列挙でのみ機能します。また、範囲外のインデックスを処理しないため、節約できるとは考えていません。

私が最終的に使用した解決策はそれほど単純ではないかもしれませんが、それは完全に節約され、大きな列挙型でもコードのパフォーマンスを損なうことはありません:

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

あなたがあなたのインデックスで決して範囲外になることはなく、あなたUNKNOWNが上記のように使用したくないと確信しているなら、もちろんあなたも行うことができます:

public static Example getById(int id) {
        return enumById.get(id);
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.