Panduan untuk EnumSet

1. Perkenalan

Dalam tutorial ini, kita akan menjelajahi koleksi EnumSet dari paket java.util dan membahas kekhasannya.

Pertama-tama kami akan menunjukkan fitur-fitur utama dari koleksi dan setelah itu, kami akan melihat bagian dalam kelas untuk memahami manfaatnya.

Terakhir, kami akan membahas operasi utama yang disediakan dan menerapkan beberapa contoh dasar.

2. Apa itu EnumSet

Sebuah EnumSet adalah khusus Set koleksi untuk bekerja dengan enum kelas . Ini mengimplementasikan antarmuka Set dan meluas dari AbstractSet :

Meskipun AbstractSet dan AbstractCollection menyediakan implementasi untuk hampir semua metode antarmuka Set dan Collection , EnumSet menimpa sebagian besar dari mereka.

Saat kami berencana menggunakan EnumSet, kami harus mempertimbangkan beberapa poin penting:

  • Ini hanya dapat berisi nilai enum dan semua nilai harus termasuk dalam enum yang sama
  • Itu tidak memungkinkan untuk menambahkan nilai null , melemparkan NullPointerException dalam upaya untuk melakukannya
  • Ini bukan thread-safe , jadi kami perlu menyinkronkannya secara eksternal jika diperlukan
  • Elemen-elemen tersebut disimpan mengikuti urutan di mana mereka dideklarasikan dalam enum
  • Ini menggunakan iterator anti-gagal yang berfungsi pada salinan, sehingga tidak akan memunculkan ConcurrentModificationException jika koleksi diubah saat melakukan iterasi di atasnya

3. Mengapa Menggunakan EnumSet

Sebagai aturan praktis, EnumSet harus selalu lebih disukai daripada implementasi Set lainnya saat kita menyimpan nilai enum .

Di bagian selanjutnya, kita akan melihat apa yang membuat koleksi ini lebih baik dari yang lain. Untuk melakukannya, kami akan menunjukkan secara singkat bagian dalam kelas untuk mendapatkan pemahaman yang lebih baik.

3.1. Detail Implementasi

EnumSet adalah kelas abstrak publik yang berisi beberapa metode pabrik statis yang memungkinkan kita membuat instance. JDK menyediakan 2 implementasi berbeda - bersifat paket-pribadi dan didukung oleh vektor bit:

  • RegularEnumSet dan
  • JumboEnumSet

RegularEnumSet menggunakan satu panjang untuk mewakili vektor bit. Setiap bit darielemen panjang mewakili nilai enum . Nilai ke-i dari enum akan disimpan di bit ke-i, jadi cukup mudah untuk mengetahui apakah suatu nilai ada atau tidak. Karena long merupakan tipe data 64-bit, implementasi ini dapat menyimpan hingga 64 elemen.

Di sisi lain, JumboEnumSet menggunakan array elemen panjang sebagai vektor bit. Ini memungkinkan implementasi ini menyimpan lebih dari 64 elemen. Ia bekerja sangat mirip dengan RegularEnumSet tetapi membuat beberapa kalkulasi tambahan untuk menemukan indeks array di mana nilainya disimpan.

Tidak mengherankan, elemen panjang pertama dari array akan menyimpan 64 nilai pertama dari enum , elemen kedua 64 berikutnya, dan seterusnya.

Metode pabrik EnumSet membuat instance dari satu implementasi atau lainnya tergantung pada jumlah elemen enum :

if (universe.length <= 64) return new RegularEnumSet(elementType, universe); else return new JumboEnumSet(elementType, universe);

Perlu diingat bahwa ini hanya memperhitungkan ukuran kelas enum , bukan jumlah elemen yang akan disimpan dalam koleksi.

3.2. Manfaat dari Menggunakan EnumSet

Karena implementasi EnumSet yang telah kami jelaskan di atas, semua metode dalam EnumSet diimplementasikan menggunakan operasi bitwise aritmatika. Perhitungan ini sangat cepat dan oleh karena itu semua operasi dasar dijalankan dalam waktu yang konstan.

Jika kita membandingkan EnumSet dengan implementasi Set lain seperti HashSet , yang pertama biasanya lebih cepat karena nilainya disimpan dalam urutan yang dapat diprediksi dan hanya satu bit yang perlu diperiksa untuk setiap komputasi. Tidak seperti HashSet , tidak perlu menghitung kode hash untuk menemukan keranjang yang tepat.

Selain itu, karena sifat vektor bit, EnumSet sangat kompak dan efisien. Oleh karena itu, ia menggunakan lebih sedikit memori, dengan semua manfaat yang dibawanya.

4. Operasi Utama

Mayoritas metode EnumSet berfungsi seperti Set lainnya , dengan pengecualian metode untuk membuat instance.

Di bagian selanjutnya, kami akan menunjukkan secara detail semua metode pembuatan dan kami akan membahas secara singkat metode lainnya.

Dalam contoh kami, kami akan bekerja dengan enum Warna :

public enum Color { RED, YELLOW, GREEN, BLUE, BLACK, WHITE }

4.1. Metode Penciptaan

Metode paling sederhana untuk membuat EnumSet adalah allOf () dan noneOf () . Dengan cara ini kita dapat dengan mudah membuat EnumSet yang berisi semua elemen enum Color kita :

EnumSet.allOf(Color.class);

Demikian juga, kita bisa menggunakan noneOf () untuk melakukan hal sebaliknya dan membuat koleksi kosong Color :

EnumSet.noneOf(Color.class);

Jika kita ingin membuat EnumSet dengan subset dari enum elemen kita dapat menggunakan kelebihan beban dari () metode . Penting untuk membedakan antara metode dengan jumlah parameter tetap hingga 5 parameter berbeda dan metode yang menggunakan vararg :

Javadoc menyatakan bahwa kinerja versi varargs bisa lebih lambat daripada yang lain karena pembuatan larik. Oleh karena itu, kita harus menggunakannya hanya jika awalnya kita perlu menambahkan lebih dari 5 elemen.

Cara lain untuk membuat subset enum adalah dengan menggunakan metode range () :

EnumSet.range(Color.YELLOW, Color.BLUE);

Dalam contoh di atas, EnumSet berisi semua elemen dari Kuning ke Biru. Mereka mengikuti urutan yang ditentukan dalam enum :

[YELLOW, GREEN, BLUE]

Perhatikan bahwa ini mencakup elemen pertama dan terakhir yang ditentukan.

Metode pabrik lain yang berguna adalah komplemenOf () yang memungkinkan kita mengecualikan elemen yang diteruskan sebagai parameter . Mari buat EnumSet dengan semua elemen Color kecuali hitam dan putih:

EnumSet.complementOf(EnumSet.of(Color.BLACK, Color.WHITE));

Jika kita mencetak koleksi ini, kita dapat melihat bahwa itu berisi semua elemen lainnya:

[RED, YELLOW, GREEN, BLUE]

Akhirnya, kita dapat membuat EnumSet dengan menyalin semua elemen dari EnumSet lain :

EnumSet.copyOf(EnumSet.of(Color.BLACK, Color.WHITE));

Secara internal, ini memanggil metode klon .

Selain itu, kami juga dapat menyalin semua elemen dari Koleksi mana pun yang berisi elemen enum . Mari kita gunakan untuk menyalin semua elemen daftar:

List colorsList = new ArrayList(); colorsList.add(Color.RED); EnumSet listCopy = EnumSet.copyOf(colorsList);

Dalam kasus ini, listCopy hanya berisi warna merah.

4.2. Operasi Lainnya

Operasi lainnya bekerja dengan cara yang sama persis seperti implementasi Set lainnya dan tidak ada perbedaan dalam cara menggunakannya.

Oleh karena itu, kita dapat dengan mudah membuat EnumSet kosong dan menambahkan beberapa elemen:

EnumSet set = EnumSet.noneOf(Color.class); set.add(Color.RED); set.add(Color.YELLOW)

Periksa apakah koleksi berisi elemen tertentu:

set.contains(Color.RED);

Iterasi elemen:

set.forEach(System.out::println);

Atau cukup hapus elemen:

set.remove(Color.RED);

Ini, tentu saja, di antara semua operasi lain yang didukung oleh Set .

5. Kesimpulan

Dalam artikel ini, kami telah menunjukkan fitur-fitur utama EnumSet , implementasi internalnya, dan bagaimana kami dapat memanfaatkannya.

Kami juga telah membahas metode utama yang ditawarkan dan menerapkan beberapa contoh untuk menunjukkan bagaimana kami dapat menggunakannya.

Seperti biasa, kode sumber lengkap dari contoh tersedia di GitHub.