Iteratorlar (Iterators)
Bir koleksiyonun elemanlarını tek tek gezmek, programlamanın en sık yaptığı işlerden biridir. Ama farklı koleksiyonların (liste, küme, kuyruk...) iç yapıları çok farklıdır. Iterator, bu farkı gizleyen ortak bir gezint…
Iteratorlar (Iterators)
Bir koleksiyonun elemanlarını tek tek gezmek, programlamanın en sık yaptığı işlerden biridir.
Ama farklı koleksiyonların (liste, küme, kuyruk...) iç yapıları çok farklıdır. Iterator, bu
farkı gizleyen ortak bir gezinti arayüzüdür: koleksiyonun tipinden bağımsız, standart bir "sıradaki
elemanı ver" mekanizması. Aslında her gün kullandığın for-each döngüsü de perde arkasında
Iterator'a dayanır.
Iterator: standart gezinti
Iterator üç metot sunar: hasNext() (daha eleman var mı?), next() (sıradakini ver) ve
isteğe bağlı remove() (son döneni sil):
Iterator<String> it = liste.iterator(); while (it.hasNext()) { String e = it.next(); ... }
for (String e : liste) yazdığında derleyici bunu tam olarak bu Iterator döngüsüne çevirir. Örnek
1 (./Ornek1.java) temel gezintiyi ve kritik bir konuyu gösterir: gezerken güvenli silme.
fail-fast ve gezerken değiştirme
Bir koleksiyonu for-each ile gezerken aynı anda liste.remove(...) çağırırsan
ConcurrentModificationException alırsın. Bu "fail-fast" davranıştır: koleksiyon, gezinti
sırasında yapısal olarak değiştiğini fark eder ve hemen hata verir (sessiz, bozuk sonuç yerine).
Doğru yollar:
- Gezerken silmek için
iterator.remove()kullan (güvenli). - Daha temizi: koşullu silme için
removeIf(predicate)(iç tarafta iterator kullanır).
it.remove(); // güvenli, gezinti sırasında liste.removeIf(s -> s.isEmpty()); // en temiz
ListIterator: çift yönlü ve güçlü
List'ler ayrıca ListIterator sunar: ileri ve geri gidebilir, gezerken güncelleyebilir
(set) ve ekleyebilir (add), konumu sorgulayabilir (nextIndex/previousIndex):
ListIterator<Integer> it = list.listIterator(); while (it.hasNext()) { int x = it.next(); it.set(x * x); } // yerinde güncelle while (it.hasPrevious()) { ... } // geri git
Örnek 2 (./Ornek2.java) bir listeyi set ile yerinde güncellemeyi, geri gezintiyi ve add ile
ekleme yapmayı gösterir.
Kendi Iterable'ını yazmak
Kendi sınıfını for-each ile gezilebilir yapmak istiyorsan Iterable<T> uygula: tek metodu
iterator()'dır ve bir Iterator<T> döndürür:
class Aralik implements Iterable<Integer> { public Iterator<Integer> iterator() { return new Iterator<>() { public boolean hasNext() { ... } public Integer next() { ... } }; } } for (int s : new Aralik(1, 5)) { ... } // artık for-each çalışır
Örnek 3 (./Ornek3.java) 1..n aralığını for-each ile gezilebilir bir Iterable olarak yazar.
Bu, kendi veri yapılarını (ağaç, grafik, sayfalı akış...) dilin doğal döngüsüne bağlamanı sağlar.
Iterator vs Enumeration
Iterator, eski Enumeration'ın (Java 1.0) halefidir; daha kısa metot adları ve remove()
desteği getirir. Eski API'lerde (Vector, Hashtable) hâlâ Enumeration görürsün; onu ayrı bir
konuda ele alıyoruz.
Özet
Koleksiyonları tipinden bağımsız gezmenin standart yolu olan Iterator'ı (Örnek 1); fail-fast
davranışını ve gezerken güvenli silmeyi (iterator.remove/removeIf); çift yönlü ve güncelleyebilen
ListIterator'ı (Örnek 2) ve kendi sınıfını for-each'e açan Iterable'ı (Örnek 3) öğrendik.
Sırada, nesneleri sıralamanın temeli — bir nesnenin "doğal sırasını" tanımlamak: Comparable
arayüzü.
▶ Kod Örnekleri(3)
Ornek1
çalıştırılabilir1// Ornek1: Iterator — bir koleksiyonu güvenle gezmek ve gezerken eleman silmek.
2// Çalıştırma: java Ornek1.java
3import java.util.ArrayList;
4import java.util.Iterator;
5import java.util.List;
6
7public class Ornek1 {
8
9 public static void main(String[] args) {
10 List<String> liste = new ArrayList<>(List.of("elma", "armut", "", "kiraz", "", "muz"));
11
12 // Iterator: hasNext() -> next() döngüsü. for-each'in arkasındaki mekanizma budur.
13 Iterator<String> it = liste.iterator();
14 System.out.print("Gezinti: ");
15 while (it.hasNext()) {
16 System.out.print(it.next() + " ");
17 }
18 System.out.println();
19
20 // GEZERKEN SİLME: for-each içinde liste.remove(...) -> ConcurrentModificationException!
21 // Doğrusu: iterator.remove() ile güvenli silme.
22 Iterator<String> it2 = liste.iterator();
23 while (it2.hasNext()) {
24 if (it2.next().isEmpty()) {
25 it2.remove(); // güvenli: iterator üzerinden sil
26 }
27 }
28 System.out.println("Boşlar silindikten sonra: " + liste);
29
30 // Aynı işi modern yol: removeIf (iç tarafta iterator kullanır)
31 liste.removeIf(s -> s.length() > 4);
32 System.out.println("4+ harfliler silindikten sonra: " + liste);
33
34 System.out.println("""
35
36 --- Iterator ---
37 Iterator, bir koleksiyonu tipinden bağımsız gezmenin standart yoludur (hasNext/next/remove).
38 for-each döngüsü aslında arka planda Iterator kullanır.
39 Gezerken eleman silmek için MUTLAKA iterator.remove() kullan; koleksiyonu doğrudan
40 değiştirmek 'fail-fast' davranışıyla ConcurrentModificationException atar.
41 Pratikte silme için 'removeIf' en temiz yoldur.""");
42 }
43}Ornek2
çalıştırılabilir1// Ornek2: ListIterator — çift yönlü gezinti + gezerken güncelleme/ekleme.
2// Çalıştırma: java Ornek2.java
3import java.util.ArrayList;
4import java.util.List;
5import java.util.ListIterator;
6
7public class Ornek2 {
8
9 public static void main(String[] args) {
10 List<Integer> sayilar = new ArrayList<>(List.of(1, 2, 3, 4));
11
12 // ListIterator yalnızca List'lerde vardır; ileri+geri gidebilir, set/add yapabilir.
13 ListIterator<Integer> it = sayilar.listIterator();
14
15 // İleri giderken her elemanı karesiyle DEĞİŞTİR (set).
16 while (it.hasNext()) {
17 int deger = it.next();
18 it.set(deger * deger); // mevcut elemanı güncelle
19 }
20 System.out.println("Kareler (set ile): " + sayilar);
21
22 // Şimdi GERİ giderek yazdır (çift yönlülük).
23 System.out.print("Geri gezinti: ");
24 while (it.hasPrevious()) {
25 System.out.print(it.previous() + " ");
26 }
27 System.out.println();
28
29 // İleri giderken araya eleman EKLE (add).
30 ListIterator<Integer> it2 = sayilar.listIterator();
31 while (it2.hasNext()) {
32 int d = it2.next();
33 if (d == 4) it2.add(-1); // 4'ten (kare: 16... burada 1,4,9,16) sonra -1 ekle
34 }
35 System.out.println("Ekleme sonrası: " + sayilar);
36 System.out.println("Index bilgisi: nextIndex=" + it2.nextIndex());
37
38 System.out.println("""
39
40 --- ListIterator ---
41 Iterator'ın List'lere özel, güçlü sürümü:
42 - çift yönlü: hasNext/next ve hasPrevious/previous,
43 - gezerken set(e) ile GÜNCELLEME, add(e) ile EKLEME,
44 - nextIndex()/previousIndex() ile konum bilgisi.
45 Bir listeyi gezerken yerinde değiştirmen gerekiyorsa ListIterator idealdir.""");
46 }
47}Ornek3
çalıştırılabilir1// Ornek3: Kendi Iterable'ını yaz — sınıfın for-each ile gezilebilsin.
2// Çalıştırma: java Ornek3.java
3import java.util.Iterator;
4import java.util.NoSuchElementException;
5
6public class Ornek3 {
7
8 public static void main(String[] args) {
9 // Kendi koleksiyon benzeri sınıfımız (1..n aralığı). Iterable olduğu için for-each çalışır.
10 Aralik aralik = new Aralik(1, 5);
11 System.out.print("for-each ile: ");
12 for (int sayi : aralik) {
13 System.out.print(sayi + " ");
14 }
15 System.out.println();
16
17 // Iterable olduğu için Stream/forEach gibi araçlara da köprü kurulabilir.
18 long toplam = 0;
19 for (int s : aralik) toplam += s;
20 System.out.println("Toplam: " + toplam);
21
22 System.out.println("""
23
24 --- Kendi Iterable'ını yazmak ---
25 Bir sınıf Iterable<T> uygularsa (iterator() metodu), for-each döngüsüyle gezilebilir.
26 iterator(), Iterator<T> döndürür: hasNext() + next() (gerekirse remove()).
27 Bu, kendi veri yapılarını (ağaç, grafik, sayfa akışı...) dilin doğal döngüsüne bağlamanı sağlar.
28 JDK'daki List/Set/Map.values() hepsi bu sözleşmeyi uygular.""");
29 }
30}
31
32// Iterable<Integer>: for-each ile gezilebilir bir tam sayı aralığı.
33class Aralik implements Iterable<Integer> {
34 private final int bas, son;
35 Aralik(int bas, int son) { this.bas = bas; this.son = son; }
36
37 @Override
38 public Iterator<Integer> iterator() {
39 return new Iterator<>() {
40 private int simdiki = bas;
41 @Override public boolean hasNext() { return simdiki <= son; }
42 @Override public Integer next() {
43 if (!hasNext()) throw new NoSuchElementException();
44 return simdiki++;
45 }
46 };
47 }
48}