CodeGym /Kurslar /Java SELF AZ /for-each döngüsü

for-each döngüsü

Java SELF AZ
Səviyyə , Dərs
Mövcuddur

1. Iteratorun yaranma tarixi

Artıq HashSet çoxluğu ilə tanışsınız. Və əgər həqiqətən onunla məşğul olmuşsunuzsa, yalnız dərsi oxumamısınızsa, bu sualı verməli idiniz:

Bəs, HashSet-in bütün elementlərini ekrana necə çıxarmaq olar? Axı, çoxluqda get()set() metodları yoxdur!

HashSet bu problemi ilə tək deyil. HashSet-dən başqa, hələ bir çox müxtəlif kolleksiyalar var, hansı ki, elementi nömrə üzrə əldə etmək mümkün deyil, çünki elementlərin dəqiq sıralaması yoxdur.

Proqramçılar bir vaxtlar qraf, ağac kimi bir çox çətin məlumat strukturları icad ediblər. Məsələn, siyahılar siyahısı.

Bir çox konteynerlər yeni elementlər əlavə edilərkən və ya mövcud elementlər çıxarıldıqda öz elementlərinin sırasını dəyişir. Məsələn, elementləri sırayla saxlayan bir siyahı var və yeni element əlavə olunduqda, bu element demək olar ki, həmişə siyahının ortasına daxil edilir.

Və belə bir vəziyyət yaranır ki, elementlərə sahib konteyner var, elementlərin özü də var, amma sabit bir sıralama yoxdur.

Amma fərz edək ki, belə bir kolleksiyadakı bütün elementləri bir massivə və ya siyahıya köçürmək istəyirik. Bütün elementləri əldə etməliyik. Bizim üçün onları hansı sırayla keçəcəyimiz önəmli deyil, əsas odur ki, təkrarlanmasın. Bunu necə edə bilərik?


2. Kolleksiyada iterator

Yuxarıda qeyd olunan problemi həll etmək üçün bir həll təklif edildi — iterator.

Iterator — kolleksiyadakı bütün elementləri keçməyə və təkrar etməməyə kömək edən xüsusi bir obyekt.

Hər hansı bir kolleksiyadan iterator əldə etmək bu kod vasitəsilə mümkündür:

Iterator<Tip> it = ad.iterator();

Burada ad — kolleksiya dəyişəninin adı, Tip — kolleksiyanın elementlərinin tipi, iterator() — kolleksiyanın metodu, it — iterator obyektinin dəyişən adı.

Iterator obyektinin 3 metodu var:

Metod Təsvir
Tip next()
Kolleksiyanın növbəti elementini qaytarır
boolean hasNext()
Hələ keçilməmiş elementlərin olub-olmadığını yoxlayır
void remove()
Kolleksiyanın cari elementini silir

Bu metodlar bir qədər Scanner sinifinin metodlarına bənzəyir: nextInt()hasNextInt().

Metod next() iterator aldığımız kolleksiyanın növbəti elementini qaytarır.

Metod hasNext() kolleksiyada iteratorun qaytarmadığı elementlərin olub-olmadığını yoxlayır.

HashSet çoxluğundakı bütün elementləri ekrana çıxarmaq üçün belə etmək olar:

Kod Qeydlər
HashSet<String> set = new HashSet<String>();

set.add("Salam");
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);
}
String tipli elementləri saxlayan HashSet tipində obyekt yaradırıq.


Müxtəlif dillərdəki salamlamaları set-ə əlavə edirik.




set çoxluğundan iterator obyektini alırıq.
Hələ elementlər varsa

Növbəti elementi əldə edirik
Elementi ekrana çıxarırıq


3. for-each dövrü

Iteratorun əsas mənfi cəhəti odur ki, onun istifadəsi ilə kod, dövr for istifadəsi ilə müqayisədə daha mürəkkəb görünür.

Gəlin, müqayisə üçün siyahını ekrana həm for dövründən, həm də iterator vasitəsilə çıxaraq:

Iterator for dövrü
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);
}

Bəli, ArrayList siyahısının elementlərini dövr ilə keçmək daha qısa və rahatdır.

Ancaq Java tərtibatçıları bizə bir az şəkər qatmağa qərar verdilər. Xoşbəxtliyimizə görə, bu yenidən sintaksis şəkəri idi.

Onlar Java-ya yeni bir dövr növü əlavə etdilər və onu for-each adlandırdılar. Onun ümumi istifadəsi belə görünür:

for(Tip ad:kolleksiya)

Burada kolleksiya — kolleksiya dəyişəni adı, Tip — kolleksiya elementlərinin tipi, ad — hər iterasiyada növbəti dəyər alan dəyişənin adıdır.

Bu dövr elementləri gizli iterator vasitəsilə keçir. Əslində onun iş prinsipi budur:

for-each dövrü Compiler’in gördüyü kod: Iterator ilə dövr
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);
}

Compiler kodunuza for-each dövrünü gördüyü zaman sadəcə sağdakı kodu əlavə edir: iterator alma metodunu və lazım olan metod çağırışlarını əlavə edir.

Proqramçılar for-each dövrünü çox sevirlər və kolleksiyanın bütün elementlərini keçmək lazım olduqda adətən onu istifadə edirlər.

Hətta ArrayList siyahısını for-each ilə keçmək qısadır:

for-each dövrü for dövrü
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. for-each dövründə elementin silinməsi

for-each dövrünün bir mənfi tərəfi var: o, elementləri düzgün silməyi bacarmır. Əgər belə bir kod yazsanız, xəta alacaqsınız.

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

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












Element silinərkən xəta baş verəcək!

Bu çox gözəl və anlaşılan bir koddur, lakin işləməyəcək.

Vacibdir!

Iterator ilə kolleksiyanı keçərkən onu dəyişmək olmaz.

Bu məhdudiyyətdən yan keçmək üçün üç üsul mövcuddur.

1 Başqa dövrün istifadəsi

Əgər ArrayList kolleksiyasını keçirsinizsə, i sayğacı ilə adi dövrdən istifadə edə bilərsiniz.

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

   if (str.equals("Hello"))
   {
      list.remove(str);
      i--;    // i-ni azaltmaq lazımdır, çünki silindikdən sonra elementlər yer dəyişir
   }
}

Amma bu variant HashSetHashMap kolleksiyaları üçün uyğun deyil

2 Iteratorun açıq istifadəsi

Iteratoru açıq şəkildə istifadə edə bilərsiniz və onun remove() metodundan istifadə edə bilərsiniz.

İşləyən variant İşləməyən variant
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); }

Nəzərə alın ki, remove() metodunu iterator obyektindən çağırırıq! Iterator elementi silmək haqqında «məlumat alacaq» və bu vəziyyəti düzgün emal edə biləcək.

3 Kolleksiyanın kopyasının istifadəsi

Eyni zamanda kolleksiyanın kopyasını yaratmaq mümkündür və for-each dövründə kopya kolleksiyanı istifadə edərək, elementləri orijinal kolleksiyadan silmək mümkündür.

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

for (String str: listCopy)
{
   if (str.equals("Hello"))
      list.remove(str);
}
Kolleksiyanın kopyasını yaratmaq çox asandır



Dövr kopya kolleksiyanın iteratorundan istifadə edir.
Elementlər list kolleksiyasından silinir.

Kolleksiyanın kopyası kifayət qədər tez yaradılır: elementlər kopyalanma zamanı dublikat edilməz, yeni kolleksiyada köhnə kolleksiyada olan eynilə həmin elementlərin bağlantıları saxlanılacaq.

Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION