1. Latar belakang tentang bagaimana iterator muncul

Anda sudah biasa dengan HashSet. Jika anda benar-benar menyiasatnya, selain daripada membaca pelajaran, maka anda sepatutnya bertanya soalan ini:

Bagaimanakah saya boleh memaparkan senarai semua elemen HashSet pada skrin? Lagipun, antara muka tidak mempunyai get()dan set()kaedah!

Dan HashSettidak bersendirian dalam had ini. Di samping itu HashSet, terdapat banyak koleksi lain yang tidak membenarkan unsur-unsur diambil oleh indeks, kerana unsur-unsur tidak mempunyai susunan yang ditentukan.

Selama bertahun-tahun, pengaturcara telah mencipta banyak struktur data yang kompleks, seperti graf dan pepohon. Atau senarai senarai.

Banyak bekas mengubah susunan elemennya apabila elemen baharu ditambah atau elemen sedia ada dialih keluar. Sebagai contoh, senarai menyimpan elemen dalam susunan tertentu dan apabila elemen baharu ditambah, ia hampir selalu disisipkan di tengah-tengah senarai.

Dan kami juga mendapat situasi di mana terdapat bekas yang menyimpan elemen tetapi tidak dalam sebarang susunan tetap.

Sekarang katakan kita mahu menyalin semua elemen daripada koleksi sedemikian ke dalam tatasusunan atau senarai. Kita perlu mendapatkan semua elemen. Kami tidak mempedulikan susunan kami mengulangi elemen — perkara penting ialah tidak mengulangi elemen yang sama lebih daripada sekali. Bagaimana kita melakukannya?


2. Iterator untuk koleksi

Iterator telah dicadangkan sebagai penyelesaian kepada masalah di atas.

Iterator ialah objek khas yang dikaitkan dengan koleksi, yang membantu melintasi semua elemen koleksi tanpa mengulangi apa-apa.

Anda boleh menggunakan kod berikut untuk mendapatkan iterator untuk sebarang koleksi:

Iterator<Type> it = name.iterator();

Di manakah namenama pembolehubah koleksi, Typeialah jenis elemen koleksi, iterator()merupakan salah satu kaedah koleksi, dan itnama pembolehubah lelaran.

Objek iterator mempunyai 3 kaedah:

Kaedah Penerangan
Type next()
Mengembalikan elemen seterusnya dalam koleksi
boolean hasNext()
Menyemak sama ada terdapat sebarang elemen yang belum dilalui
void remove()
Mengalih keluar elemen semasa koleksi

Kaedah ini agak serupa dengan kelas nextInt)dan hasNextInt()kaedah Pengimbas.

Kaedah ini next()mengembalikan elemen koleksi seterusnya dari mana kami mendapat iterator.

Kaedah hasNext()menyemak sama ada koleksi mempunyai elemen tambahan yang belum dikembalikan oleh iterator.

Berikut ialah cara untuk memaparkan semua elemen a HashSet:

Kod Nota
HashSet<String> set = new HashSet<String>();

set.add("Hallo");
set.add("Hello");
set.add("Hola");
set.add("Bonjour");
set.add("Ciao");
set.add("Namaste");

Iterator<String> it = set.iterator();
while (it.hasNext())
{
   String str = it.next();
   System.out.println(str);
}
Buat HashSetobjek yang menyimpan Stringelemen.


Kami menambah ucapan dalam pelbagai bahasa kepada setpembolehubah.




Dapatkan objek iterator untuk setset.
Selagi masih ada elemen

Dapatkan elemen seterusnya
Paparkan elemen pada skrin


3. For-eachgelung

Kelemahan utama iterator ialah kod anda menjadi lebih rumit daripada menggunakan forgelung.

Untuk membandingkan, mari paparkan senarai menggunakan forgelung dan juga menggunakan iterator:

Iterator untuk gelung
ArrayList<String> list = new ArrayList<String>();

Iterator<String> it = list.iterator();
while (it.hasNext())
{
   String str = it.next();
   System.out.println(str);
}
ArrayList<String> list = new ArrayList<String>();

for (int i = 0; i < list.size(); i++)
{
   String str = list.get(i);
   System.out.println(str);
}

Ya, adalah lebih baik untuk melintasi elemen menggunakan ArrayListgelung — semuanya ternyata lebih pendek.

Tetapi pencipta Java sekali lagi memutuskan untuk mencurahkan sedikit gula kepada kami. Nasib baik bagi kami, ia adalah gula sintaksis .

Mereka memberikan Java jenis gelung baharu dan memanggilnya gelung for-each. Begini rupanya secara umum:

for(Type name:collection)

Di manakah collectionnama pembolehubah koleksi, Typeialah jenis elemen dalam koleksi, dan nameialah nama pembolehubah yang mengambil nilai seterusnya daripada koleksi pada setiap lelaran gelung.

Gelung jenis ini berulang melalui semua elemen koleksi menggunakan lelaran tersirat. Inilah cara ia sebenarnya berfungsi:

Untuk-setiap gelung Perkara yang dilihat oleh pengkompil: Gelung dengan lelaran
ArrayList<String> list = new ArrayList<String>();

for (String str: list)
{
   System.out.println(str);
}
ArrayList<String> list = new ArrayList<String>();
Iterator<String> it = list.iterator();

while (it.hasNext())
{
   String str = it.next();
   System.out.println(str);
}

Apabila pengkompil menemui for-eachgelung dalam kod anda, ia hanya menggantikannya dengan kod di sebelah kanan: ia menambah panggilan untuk mendapatkan lelaran bersama-sama dengan mana-mana panggilan kaedah lain yang hilang.

Pengaturcara menyukai for-eachgelung dan hampir selalu menggunakannya apabila mereka perlu mengulangi semua elemen koleksi.

Malah mengulang ArrayListsenarai menggunakan for-eachgelung kelihatan lebih pendek:

Untuk-setiap gelung untuk gelung
ArrayList<String> list = new ArrayList<String>();

for (String str: list)
{
   System.out.println(str);
}
ArrayList<String> list = new ArrayList<String>();

for (int i = 0; i < list.size(); i++)
{
   String str = list.get(i);
   System.out.println(str);
}


4. Mengalih keluar elemen dalam for-eachgelung

Gelung for-eachmempunyai satu kelemahan: ia tidak boleh mengalih keluar elemen dengan betul. Jika anda menulis kod seperti ini, anda akan mendapat ralat.

Kod Catatan
ArrayList<String> list = new ArrayList<String>();

list.add("Hallo");
list.add("Hello");
list.add("Hola");
list.add("Bonjour");
list.add("Ciao");
list.add("Namaste");

for (String str: list)
{
   if (str.equals("Hello"))
      list.remove(str);
}












Operasi alih keluar akan menghasilkan ralat!

Ini adalah kod yang sangat bagus dan mudah difahami, tetapi ia tidak akan berfungsi.

Penting!

Anda tidak boleh menukar koleksi semasa anda melintasinya dengan iterator.

Terdapat tiga cara untuk mengatasi had ini.

1. Gunakan jenis gelung yang berbeza

When traversing an ArrayList collection, anda boleh menggunakan gelung biasa dengan ipembolehubah pembilang.

Kod
for (int i = 0; i < list.size(); i++)
{
   String str = list.get(i);

   if (str.equals("Hello"))
   {
      list.remove(str);
      i--; // We need to decrease i, because the remove operation shifted the elements
   }
}

Walau bagaimanapun, pilihan ini tidak sesuai untuk HashSetdan HashMapkoleksi

2. Gunakan iterator eksplisit

Anda boleh menggunakan iterator secara eksplisit dan memanggil kaedahnya remove().

Versi yang berfungsi Versi yang tidak berfungsi
Iterator<String> it = set.iterator();
while (it.hasNext())
{
   String str = it.next();
   if (str.equals("Hello"))
       it.remove();
}

for (String str: list) { if (str.equals("Hello")) list.remove(str); }

Perhatikan bahawa kami memanggil remove()kaedah pada objek iterator! Peulang sedar bahawa item telah dialih keluar dan boleh mengendalikan situasi dengan betul.

3. Gunakan salinan koleksi

Anda juga boleh membuat salinan koleksi dan kemudian menggunakan salinan dalam gelung for-eachdan memadamkan elemen daripada koleksi asal.

Kod Catatan
ArrayList<String> listCopy = new ArrayList(list);

for (String str: listCopy)
{
   if (str.equals("Hello"))
      list.remove(str);
}
Mencipta salinan koleksi adalah sangat mudah



Gelung menggunakan lelaran untuk salinan koleksi.
Elemen dialih keluar daripada listkoleksi.

Koleksi disalin agak cepat, kerana elemen itu sendiri tidak diduplikasi. Sebaliknya, koleksi baharu menyimpan rujukan kepada elemen yang telah wujud dalam koleksi lama.