1. Yineleyicilerin nasıl ortaya çıktığına dair arka plan

zaten aşinasınız HashSet. Sadece bir ders okumanın ötesinde gerçekten araştırdıysanız, şu soruyu sormanız gerekirdi:

Ekranda tüm HashSet öğelerinin listesini nasıl görüntülerim? get()Sonuçta, arayüz ve set()yöntemler yok !

Ve HashSetbu sınırlamada yalnız değil. Ek olarak HashSet, öğelerin tanımlı bir sırası olmadığı için öğelerin dizine göre alınmasına izin vermeyen birçok başka koleksiyon vardır.

Yıllar geçtikçe, programcılar grafikler ve ağaçlar gibi birçok karmaşık veri yapısı icat ettiler. Veya liste listeleri.

Birçok konteyner, yeni öğeler eklendiğinde veya mevcut öğeler kaldırıldığında öğelerinin sırasını değiştirir. Örneğin, bir liste, öğeleri belirli bir sırada saklar ve yeni bir öğe eklendiğinde, hemen hemen her zaman listenin ortasına eklenir.

Ayrıca öğeleri depolayan ancak herhangi bir sabit sırada olmayan bir kapsayıcının olduğu durumlar da elde ederiz.

Şimdi böyle bir koleksiyondaki tüm öğeleri bir diziye veya listeye kopyalamak istediğimizi varsayalım. Tüm unsurları almamız gerekiyor. Öğeler üzerinde yineleme sırasını umursamıyoruz - önemli olan aynı öğeler üzerinde birden fazla yineleme yapmamaktır. Bunu nasıl yaparız?


2. Bir koleksiyon için yineleyici

Yineleyiciler, yukarıdaki soruna bir çözüm olarak önerildi.

Bir yineleyici, bir koleksiyonla ilişkili özel bir nesnedir ve koleksiyonun tüm öğelerini hiçbirini tekrar etmeden dolaşmaya yardımcı olur.

Herhangi bir koleksiyon için bir yineleyici almak üzere aşağıdaki kodu kullanabilirsiniz:

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

nameKoleksiyon değişkeninin adı, koleksiyonun Typeöğelerinin türü, iterator()koleksiyonun yöntemlerinden biri ve ityineleyici değişkenin adıdır.

Bir yineleyici nesnenin 3 yöntemi vardır:

Yöntem Tanım
Type next()
Koleksiyondaki bir sonraki öğeyi döndürür
boolean hasNext()
Henüz geçilmemiş herhangi bir öğe olup olmadığını kontrol eder
void remove()
Koleksiyonun geçerli öğesini kaldırır

Bu yöntemler, Scanner sınıfının nextInt)ve hasNextInt()yöntemlerine biraz benzer.

Yöntem next(), yineleyiciyi aldığımız koleksiyonun bir sonraki öğesini döndürür.

Yöntem hasNext(), koleksiyonun yineleyicinin henüz döndürmediği ek öğelere sahip olup olmadığını kontrol eder.

a öğesinin tüm öğelerini nasıl görüntüleyeceğiniz aşağıda açıklanmıştır HashSet:

kod notlar
HashSet<String> set = new HashSet<String>();

set.add("Hello");
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);
}
HashSetÖğeleri depolayan bir nesne oluşturun String.


Değişkene çeşitli dillerdeki selamları ekliyoruz set.




Küme için bir yineleyici nesnesi alın set.
Hala öğeler olduğu sürece

Sonraki öğeyi al
Öğeyi ekranda göster


3. For-eachdöngü

Bir yineleyicinin ana dezavantajı, kodunuzun bir fordöngü kullanmaktan daha hantal hale gelmesidir.

forKarşılaştırmak için, bir döngü ve yineleyici kullanarak bir liste görüntüleyelim :

Yineleyici döngü için
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);
}

Evet, bir döngü kullanarak öğelerini geçmek çok daha iyidir ArrayList— her şeyin daha kısa olduğu ortaya çıkar.

Ancak Java'nın yaratıcıları yine üzerimize biraz şeker dökmeye karar verdi. Neyse ki bizim için sözdizimsel şekerdi .

Java'ya yeni bir tür döngü verdiler ve buna for-eachdöngü adını verdiler. Genel olarak böyle görünüyor:

for(Type name:collection)

collectionKoleksiyon değişkeninin adı nerede , Typekoleksiyondaki öğelerin türü ve namedöngünün her yinelemesinde koleksiyondan bir sonraki değeri alan değişkenin adı.

Bu tür bir döngü, örtük bir yineleyici kullanarak bir koleksiyonun tüm öğelerini yineler. Gerçekte şöyle çalışır:

Her döngü için Derleyici ne görür: Bir yineleyici ile döngü
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);
}

Derleyici for-eachkodunuzda bir döngüyle karşılaştığında, onu sağdaki kodla değiştirir: diğer eksik yöntem çağrılarıyla birlikte bir yineleyici almak için bir çağrı ekler.

Programcılar döngüyü severler for-eachve bir koleksiyonun tüm öğelerini yinelemeleri gerektiğinde neredeyse her zaman onu kullanırlar.

ArrayListBir döngü kullanarak bir listeyi yinelemek bile for-eachdaha kısa görünür:

Her döngü için döngü için
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. Döngüdeki bir öğeyi for-eachçıkarma

Döngünün for-eachbir dezavantajı vardır: öğeleri doğru şekilde kaldıramaz. Böyle bir kod yazarsanız, bir hata alırsınız.

kod Not
ArrayList<String> list = new ArrayList<String>();

list.add("Hello");
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);
}












Kaldırma işlemi bir hata üretecek!

Bu çok güzel ve anlaşılır bir kod ama işe yaramayacak.

Önemli!

Bir yineleyici ile üzerinde gezinirken bir koleksiyonu değiştiremezsiniz.

Bu sınırlamayı aşmanın üç yolu vardır.

1. Farklı türde bir döngü kullanın

When traversing an ArrayList collection, bir sayaç değişkeni ile sıradan bir döngü kullanabilirsiniz i.

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

HashSetAncak bu seçenek koleksiyonlar için uygun değildir HashMap.

2. Açık bir yineleyici kullanın

Açıkça bir yineleyici kullanabilir ve yöntemini çağırabilirsiniz remove().

Çalışan sürüm Çalışmayan sürüm
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); }

remove()Yöntemi yineleyici nesnesinde çağırdığımıza dikkat edin ! Yineleyici, öğenin kaldırıldığının farkındadır ve durumu doğru bir şekilde halledebilir.

3. Koleksiyonun bir kopyasını kullanın

Ayrıca koleksiyonun bir kopyasını oluşturabilir ve ardından bu kopyayı bir döngüde kullanabilir for-eachve orijinal koleksiyondaki öğeleri silebilirsiniz.

kod Not
ArrayList<String> listCopy = new ArrayList(list);

for (String str: listCopy)
{
   if (str.equals("Hello"))
      list.remove(str);
}
Bir koleksiyonun kopyasını oluşturmak çok kolaydır Döngü,



koleksiyonun kopyası için yineleyiciyi kullanır.
Öğeler koleksiyondan kaldırılır list.

Öğelerin kendileri çoğaltılmadığı için koleksiyon oldukça hızlı bir şekilde kopyalanır. Bunun yerine, yeni koleksiyon, eski koleksiyonda zaten var olan öğelere yapılan başvuruları depolar.