Coba di MyEnum.values()[x]mana xharus 0atau 1, yaitu ordinal yang valid untuk enum itu.
Perhatikan bahwa dalam Java enum sebenarnya adalah kelas (dan nilai enum dengan demikian adalah objek) dan dengan demikian Anda tidak dapat melemparkan intatau bahkan Integerke enum.
+1: Anda mungkin ingin melakukan cache MyEnum.values()karena harganya mahal. yaitu jika Anda menyebutnya ratusan kali.
Peter Lawrey
6
@PeterLawrey Hanya untuk kelengkapan, bisakah Anda menjelaskan mengapa itu harus lambat? Saya tidak melihat alasan yang jelas untuk itu.
Tarrasch
48
@ Tarrasch karena array dapat diubah, nilai () harus mengembalikan salinan array elemen kalau-kalau Anda mengubahnya. Membuat salinan ini setiap kali relatif mahal.
Peter Lawrey
9
@PeterLawrey Saya telah menggunakan banyak haskell akhir-akhir ini (di mana semuanya tidak berubah)! Terima kasih atas penjelasan Anda yang jelas dan ringkas. :)
Tarrasch
bagaimana cara mendapatkan 'x'?
Beeing Jk
161
MyEnum.values()[x]adalah operasi yang mahal. Jika kinerjanya mengkhawatirkan, Anda mungkin ingin melakukan sesuatu seperti ini:
Jika Anda ingin menghindari pemeliharaan sakelar, maka pada kelas using: private final MyEnum [] myEnumValues = MyEnum.values (); Kemudian penggunaan: myEnum = myEnumValues [i];
Gili Nachum
23
@GiliNachum mengatakannya dengan cara yang aneh, tetapi masalah dengan solusi ini adalah rawatan. Ini bertentangan dengan prinsip KERING, yang berarti setiap kali nilai enum diubah (disusun ulang, nilai ditambahkan, nilai dihapus) pernyataan switch harus diperbarui secara bersamaan. Komentar Gili memaksa Jawa untuk mempertahankan konsistensi dengan daftar nilai enum, perubahan pada nilai enum tidak mempengaruhi pendekatan itu sama sekali.
Dandre Allison
3
@LorenzoPolidori, dapatkah Anda menjelaskan mengapa Anda menganggapnya MyEnum.values()[x]sebagai operasi yang mahal. Saya tidak tahu cara kerjanya secara detail, tetapi bagi saya sepertinya mengakses elemen dalam Array bukan masalah besar, alias waktu yang konstan. Jika array harus dibangun, dibutuhkan O (n) waktu, yang merupakan waktu runnning yang sama dengan solusi Anda.
brunsgaard
1
@ brunsgaard Saya berasumsi values()menghasilkan array baru setiap kali, karena array bisa berubah sehingga tidak aman untuk mengembalikan yang sama beberapa kali. Beralih pernyataan tidak harus O (n), mereka dapat dikompilasi ke tabel lompatan. Jadi klaim Lorenzo tampaknya bisa dibenarkan.
MikeFHay
1
@Johnson Gili versi tidak memerlukan perubahan kode tambahan di luar perubahan dalam deklarasi Enum. Jika Anda menambahkan item baru ke enum, myEnum = myEnumValues[i]masih akan mengembalikan iitem th di Enum tanpa perubahan.
Dandre Allison
45
Jika Anda ingin memberikan nilai integer Anda, Anda dapat menggunakan struktur seperti di bawah ini
publicenum A
{
B(0),
C(10),None(11);int id;private A(int i){id = i;}publicintGetID(){return id;}publicbooleanIsEmpty(){returnthis.equals(A.None);}publicbooleanCompare(int i){return id == i;}publicstatic A GetValue(int _id){
A[]As= A.values();for(int i =0; i <As.length; i++){if(As[i].Compare(_id))returnAs[i];}return A.None;}}
+1 karena menyoroti fakta, bahwa nilai tidak harus berturut-turut.
rhavin
Selain itu, ini tampaknya menjadi satu-satunya jawaban yang berfungsi jika Anda menginginkan sekumpulan nilai integer yang jarang (atau berulang) daripada menggunakan ordinals default dari 0 .. (hitung-1). Itu bisa menjadi penting jika Anda berinteraksi dengan kode yang ada, seperti melalui jaringan.
benkc
Layak menunjukkan bahwa seperti dalam jawaban di atas, caching hasil nilai () mungkin bermanfaat, sehingga untuk menghindari alokasi memori dan arraycopy setiap kali Anda memintanya.
benkc
1
Dan, tergantung pada panjang enum Anda, Anda mungkin ingin membuat HashMap atau menggunakan pencarian biner atau sesuatu untuk pencarian ini, daripada melakukan pencarian linear setiap waktu.
benkc
2
Ini harus menjadi cara yang benar dan praktik terbaik untuk mengonversi int menjadi enum, dan saya pikir Anda dapat menyederhanakan masalah dengan public static A GetValue (int _id) {for (A: A.values () {if (a.getId ( ) == _ id) {return a;}} return null;} Singkirkan barang-barang None, isEmpty () dan bandingkan ()
Chris.Zou
35
Anda bisa coba seperti ini.
Buat Kelas dengan id elemen.
publicEnumMyEnum{
THIS(5),
THAT(16),
THE_OTHER(35);privateint id;// Could be other data type besides intprivateMyEnum(int id){this.id = id;}publicstaticMyEnum fromId(int id){for(MyEnum type : values()){if(type.getId()== id){return type;}}returnnull;}}
Sekarang Ambil Enum ini menggunakan id sebagai int.
Ini adalah solusi yang saya gunakan sekarang. Tapi IMHO itu kurang membingungkan jika Anda tidak memberikan bidang valuesnama yang sama dengan metode values(). Saya menggunakan cachedValuesuntuk nama bidang.
ToolmakerSteve
2
Efisien dan elegan; disalin dan disisipkan ke proyek saya :) Satu-satunya hal yang saya ubah adalah fromInt (int i), yang baru saja saya panggil dari (int i) karena agak berlebihan untuk memiliki int dua kali dalam tanda tangan.
pipedreambomb
1
mengapa tidak menginisialisasi dari awal? mengapa menunggu hit pertama?
kaiser
9
Java enum tidak memiliki pemetaan enum-ke-int yang sama dengan yang mereka lakukan di C ++.
Yang mengatakan, semua enum memiliki valuesmetode yang mengembalikan array nilai enum yang mungkin, jadi
MyEnum enumValue =MyEnum.values()[x];
harus bekerja. Agak jahat dan mungkin lebih baik untuk tidak mencoba dan mengkonversi dari ints ke Enums (atau sebaliknya) jika memungkinkan.
Ini bukan sesuatu yang biasanya dilakukan, jadi saya akan mempertimbangkan kembali. Tetapi setelah mengatakan itu, operasi mendasar adalah: int -> enum menggunakan EnumType.values () [intNum], dan enum -> int menggunakan enumInst.ordinal ().
Namun, karena implementasi nilai apa pun () tidak punya pilihan selain memberi Anda salinan array (array java tidak pernah hanya baca), Anda akan lebih baik dilayani menggunakan EnumMap untuk cache pemetaan enum -> int.
Re "Ini bukan sesuatu yang biasanya dilakukan": Kasus umum di mana berguna: enum sesuai dengan nilai int yang disimpan dalam database.
ToolmakerSteve
@ToolmakerSteve Anda benar bahwa pemetaan diperlukan. Tapi apakah Anda ingin meninggalkan pengkodean semacam itu ke beberapa ATAU mapper atau toolkit / perpustakaan?
Dilum Ranatunga
7
Menggunakan MyEnum enumValue = MyEnum.values()[x];
Inilah solusi yang saya rencanakan. Ini tidak hanya berfungsi dengan integer non-sekuensial, tetapi juga dapat bekerja dengan tipe data lain yang mungkin ingin Anda gunakan sebagai id yang mendasari nilai enum Anda.
publicEnumMyEnum{
THIS(5),
THAT(16),
THE_OTHER(35);privateint id;// Could be other data type besides intprivateMyEnum(int id){this.id = id;}publicint getId(){returnthis.id;}publicstaticMap<Integer,MyEnum> buildMap(){Map<Integer,MyEnum> map =newHashMap<Integer,MyEnum>();MyEnum[] values =MyEnum.values();for(MyEnum value : values){
map.put(value.getId(), value);}return map;}}
Saya hanya perlu mengonversi id ke enum pada waktu tertentu (saat memuat data dari file), jadi tidak ada alasan bagi saya untuk menyimpan Peta di memori setiap saat. Jika Anda benar-benar membutuhkan peta agar dapat diakses setiap saat, Anda dapat selalu menyimpannya sebagai anggota statis kelas Enum Anda.
IMHO jika saya khawatir tentang penggunaan memori, saya akan secara dinamis membuat HashMap - seperti @ossys tetapi dengan kode yang berbeda ketika cache nol, kemudian menambahkan metode kedua clearCachedValuesketika Anda selesai menggunakannya (yang menetapkan bidang pribadi kembali ke nol). Saya menganggap MyEnum.fromInt(i)lebih mudah dipahami daripada melewati objek peta.
ToolmakerSteve
6
Jika itu membantu orang lain, opsi yang saya pilih, yang tidak tercantum di sini, menggunakan fungsionalitas Peta Guava :
Dengan default yang dapat Anda gunakan null, Anda bisa throw IllegalArgumentExceptionatau Anda fromIntbisa mengembalikan Optional, perilaku apa pun yang Anda inginkan.
Anda harus menyebutkan bahwa Anda menggunakan Jambu Biji. Atau Anda dapat menggunakan stream:Map<Integer, MyEnum> reverseLookup = Arrays.stream(MyEnum.values()).collect(Collectors.toMap(MyEnum::getValue, Function.identity()));
shmosel
1
Mungkin ingin mendefinisikan getValue()metode juga.
shmosel
@shosel Ups, saya melewatkan fungsi getValue, terima kasih. Mengetik versi generik ke dalam stackoverflow tidak selalu berjalan dengan baik. Menambahkan komentar tentang menggunakan Guava dengan tautan. Lebih suka metode Jambu ke stream.
Chad Befus
4
Anda dapat beralih lebih values()dari enum dan membandingkan nilai integer enum dengan yang diberikan idseperti di bawah ini:
publicenumTestEnum{None(0),Value1(1),Value2(2),Value3(3),Value4(4),Value5(5);privatefinalint value;privateTestEnum(int value){this.value = value;}publicint getValue(){return value;}publicstaticTestEnum getEnum(int value){for(TestEnum e:TestEnum.values()){if(e.getValue()== value)return e;}returnTestEnum.None;//For values out of enum scope}}
Dan gunakan seperti ini: TestEnum x = TestEnum.getEnum(4);//Will return TestEnum.Value4
Saya harap ini membantu;)
Pilihan yang baik adalah menghindari konversi dari intmenjadienum : misalnya, jika Anda membutuhkan nilai maksimal, Anda dapat membandingkan x.ordinal () ke y.ordinal () dan mengembalikan x atau y secara bersamaan. (Anda mungkin perlu memesan ulang nilai-nilai Anda agar perbandingan tersebut bermakna.)
Jika itu tidak mungkin, saya akan menyimpan MyEnum.values()ke array statis.
Jika Anda mendapatkan int dari DB dan ingin mengubahnya menjadi Enum, yang saya pikir adalah tugas yang sangat umum, Anda akan memerlukan int -> konversi enum, IMO ..
Yuki Inoue
0
Ini adalah jawaban yang sama dengan dokter tetapi ini menunjukkan bagaimana cara menghilangkan masalah dengan array yang bisa berubah. Jika Anda menggunakan pendekatan semacam ini karena prediksi cabang terlebih dahulu jika akan memiliki efek sangat kecil ke nol dan seluruh kode hanya memanggil nilai array yang dapat diubah () hanya berfungsi sekali. Karena kedua variabel statis, mereka tidak akan menggunakan memori n * untuk setiap penggunaan enumerasi ini juga.
privatestaticboolean arrayCreated =false;privatestaticRFMsgType[]ArrayOfValues;publicstaticRFMsgTypeGetMsgTypeFromValue(intMessageID){if(arrayCreated ==false){ArrayOfValues=RFMsgType.values();}for(int i =0; i <ArrayOfValues.length; i++){if(ArrayOfValues[i].MessageIDValue==MessageID){returnArrayOfValues[i];}}returnRFMsgType.UNKNOWN;}
Tulis implementasi ini. Ini memungkinkan untuk nilai yang hilang, nilai negatif dan menjaga kode konsisten. Peta juga di-cache. Menggunakan antarmuka dan membutuhkan Java 8.
Jawaban:
Coba di
MyEnum.values()[x]
manax
harus0
atau1
, yaitu ordinal yang valid untuk enum itu.Perhatikan bahwa dalam Java enum sebenarnya adalah kelas (dan nilai enum dengan demikian adalah objek) dan dengan demikian Anda tidak dapat melemparkan
int
atau bahkanInteger
ke enum.sumber
MyEnum.values()
karena harganya mahal. yaitu jika Anda menyebutnya ratusan kali.MyEnum.values()[x]
adalah operasi yang mahal. Jika kinerjanya mengkhawatirkan, Anda mungkin ingin melakukan sesuatu seperti ini:sumber
MyEnum.values()[x]
sebagai operasi yang mahal. Saya tidak tahu cara kerjanya secara detail, tetapi bagi saya sepertinya mengakses elemen dalam Array bukan masalah besar, alias waktu yang konstan. Jika array harus dibangun, dibutuhkan O (n) waktu, yang merupakan waktu runnning yang sama dengan solusi Anda.values()
menghasilkan array baru setiap kali, karena array bisa berubah sehingga tidak aman untuk mengembalikan yang sama beberapa kali. Beralih pernyataan tidak harus O (n), mereka dapat dikompilasi ke tabel lompatan. Jadi klaim Lorenzo tampaknya bisa dibenarkan.myEnum = myEnumValues[i]
masih akan mengembalikani
item th di Enum tanpa perubahan.Jika Anda ingin memberikan nilai integer Anda, Anda dapat menggunakan struktur seperti di bawah ini
sumber
Anda bisa coba seperti ini.
Buat Kelas dengan id elemen.
Sekarang Ambil Enum ini menggunakan id sebagai int.
sumber
Saya menyimpan nilai-nilai dan membuat metode akses statis sederhana:
sumber
values
nama yang sama dengan metodevalues()
. Saya menggunakancachedValues
untuk nama bidang.Java enum tidak memiliki pemetaan enum-ke-int yang sama dengan yang mereka lakukan di C ++.
Yang mengatakan, semua enum memiliki
values
metode yang mengembalikan array nilai enum yang mungkin, jadiharus bekerja. Agak jahat dan mungkin lebih baik untuk tidak mencoba dan mengkonversi dari
int
s keEnum
s (atau sebaliknya) jika memungkinkan.sumber
Ini bukan sesuatu yang biasanya dilakukan, jadi saya akan mempertimbangkan kembali. Tetapi setelah mengatakan itu, operasi mendasar adalah: int -> enum menggunakan EnumType.values () [intNum], dan enum -> int menggunakan enumInst.ordinal ().
Namun, karena implementasi nilai apa pun () tidak punya pilihan selain memberi Anda salinan array (array java tidak pernah hanya baca), Anda akan lebih baik dilayani menggunakan EnumMap untuk cache pemetaan enum -> int.
sumber
Menggunakan
MyEnum enumValue = MyEnum.values()[x];
sumber
Inilah solusi yang saya rencanakan. Ini tidak hanya berfungsi dengan integer non-sekuensial, tetapi juga dapat bekerja dengan tipe data lain yang mungkin ingin Anda gunakan sebagai id yang mendasari nilai enum Anda.
Saya hanya perlu mengonversi id ke enum pada waktu tertentu (saat memuat data dari file), jadi tidak ada alasan bagi saya untuk menyimpan Peta di memori setiap saat. Jika Anda benar-benar membutuhkan peta agar dapat diakses setiap saat, Anda dapat selalu menyimpannya sebagai anggota statis kelas Enum Anda.
sumber
clearCachedValues
ketika Anda selesai menggunakannya (yang menetapkan bidang pribadi kembali ke nol). Saya menganggapMyEnum.fromInt(i)
lebih mudah dipahami daripada melewati objek peta.Jika itu membantu orang lain, opsi yang saya pilih, yang tidak tercantum di sini, menggunakan fungsionalitas Peta Guava :
Dengan default yang dapat Anda gunakan
null
, Anda bisathrow IllegalArgumentException
atau AndafromInt
bisa mengembalikanOptional
, perilaku apa pun yang Anda inginkan.sumber
Map<Integer, MyEnum> reverseLookup = Arrays.stream(MyEnum.values()).collect(Collectors.toMap(MyEnum::getValue, Function.identity()));
getValue()
metode juga.Anda dapat beralih lebih
values()
dari enum dan membandingkan nilai integer enum dengan yang diberikanid
seperti di bawah ini:Dan gunakan seperti ini:
TestEnum x = TestEnum.getEnum(4);//Will return TestEnum.Value4
Saya harap ini membantu;)
sumber
Berdasarkan jawaban @ChadBefus dan komentar @shmosel, saya sarankan menggunakan ini. (Pencarian efisien, dan berfungsi di java murni> = 8)
sumber
Pilihan yang baik adalah menghindari konversi dari
int
menjadienum
: misalnya, jika Anda membutuhkan nilai maksimal, Anda dapat membandingkan x.ordinal () ke y.ordinal () dan mengembalikan x atau y secara bersamaan. (Anda mungkin perlu memesan ulang nilai-nilai Anda agar perbandingan tersebut bermakna.)Jika itu tidak mungkin, saya akan menyimpan
MyEnum.values()
ke array statis.sumber
Ini adalah jawaban yang sama dengan dokter tetapi ini menunjukkan bagaimana cara menghilangkan masalah dengan array yang bisa berubah. Jika Anda menggunakan pendekatan semacam ini karena prediksi cabang terlebih dahulu jika akan memiliki efek sangat kecil ke nol dan seluruh kode hanya memanggil nilai array yang dapat diubah () hanya berfungsi sekali. Karena kedua variabel statis, mereka tidak akan menggunakan memori n * untuk setiap penggunaan enumerasi ini juga.
sumber
sumber
Di Kotlin:
Pemakaian:
sumber
Tulis implementasi ini. Ini memungkinkan untuk nilai yang hilang, nilai negatif dan menjaga kode konsisten. Peta juga di-cache. Menggunakan antarmuka dan membutuhkan Java 8.
Enum
Antarmuka
sumber