Tek İş, Birkaç Araç
Bir miktar veri topladın - bir ArrayList, bir HashSet, bir HashMap içinde - ve şimdi her elemanı ziyaret etmek istiyorsun. Java bunu yapmanın birkaç yolunu sunar ve hangisini seçeceğin; indekse ihtiyaç duyup duymadığına, döngünün ortasında eleman çıkarman gerekip gerekmediğine ve metot tarzı mı yoksa döngü tarzı bir söz dizimini mi tercih ettiğine bağlıdır.
İyi haber: her Collection (liste, küme, kuyruk) aynı gelişmiş for döngüsünü destekler, yani onu bir kez öğrendiğinde hepsini aynı şekilde dolaşabilirsin.
İki noktayı "içindeki" olarak oku: "langs içindeki her lang için". Hiçbir zaman bir indekse dokunmazsın, dolayısıyla yanlış yapacak bir şey yoktur.
for-each Döngüsü
Gelişmiş for, sade "her elemanla bir şey yap" durumu için varsayılan tercihtir. Anlaşılır okunur ve koleksiyon türleri arasında aynı şekilde çalışır - işte hiç indeksi olmayan bir HashSet:
Bir HashSet hakkında hatırlanması gereken bir şey: tanımlı bir sırası yoktur, bu yüzden elemanlar herhangi bir sırayla yazdırılabilir. for-each yine de hepsini tam olarak bir kez ziyaret eder.
İndekse İhtiyaç Duyduğunda
for-each sana elemanı verir ama konumunu değil. İndekse gerçekten ihtiyacın varsa - satırları numaralandırmak veya komşu elemanlara bakmak için - size() ve get(i) ile sayaçlı bir döngü kullan. Bu, konumsal olan bir List üzerinde çalışır; kümelerin ve haritaların indeksi yoktur, bu yüzden bu tarz onlara uygulanmaz.
Buna sırf alışkanlıktan başvurma. i'yi get(i) dışında hiçbir şey için kullanmıyorsan, for-each sürümü daha kısadır ve yanlış yapması daha zordur.
Bir Map Üzerinde Gezinme
Bir Map, Collection değildir, bu yüzden onun üzerinde doğrudan for-each yapamazsın. Bunun yerine üç görünümünden biri üzerinde dönersin. En yaygını, her anahtar-değer çiftini birlikte sana veren entrySet()'tir:
Yalnızca anahtarlara ihtiyacın varsa ages.keySet() üzerinde dön; yalnızca değerlere ihtiyacın varsa ages.values() üzerinde dön. İkisine de ihtiyacın olduğunda entrySet()'i tercih et - anahtarlar üzerinde dönüp sonra içeride ages.get(key) çağırmak, her yinelemede gereksiz yere ikinci bir arama yapar.
Iterator
for-each aslında bir Iterator üzerine kurulu söz dizimsel bir kolaylıktır - bir koleksiyonu hasNext() ve next() aracılığıyla her seferinde bir eleman dolaşan bir nesne. Bu döngüyü elle nadiren yazarsın, önemli bir istisnayla: gezinirken eleman çıkarmanın güvenli yolu budur.
it.remove(), next()'in en son döndürdüğü elemanı siler ve yineleyici geçerli kalır. Bu, elle yapılan bir döngü sırasında bir koleksiyonu değiştirmenin onaylanmış tek yoludur.
Tuzak: ConcurrentModificationException
Bir for-each döngüsü içinde koleksiyonun kendisinde add veya remove çağırırsan, bir ConcurrentModificationException alırsın - yineleyici koleksiyonun altından değiştiğini fark eder ve devam etmeyi reddeder. Bu, en yaygın başlangıç hatalarından biridir.
List<Integer> nums = new ArrayList<>(List.of(1, 2, 3, 4));
for (int n : nums) {
if (n % 2 == 0) {
nums.remove(Integer.valueOf(n)); // throws ConcurrentModificationException
}
}
Çözüm neredeyse her zaman removeIf'tir; niyeti tek satırda ifade eder ve yinelemeyi senin yerine halleder:
removeIf herhangi bir Collection üzerinde çalışır, bu yüzden aynı çağrı bir HashSet'i de temizler.
forEach Metodu
Her koleksiyonun ayrıca bir lambda alan ve onu her eleman üzerinde çalıştıran bir forEach metodu vardır. Döngüye göre daha işlevsel, ifade tarzı bir alternatiftir - kısa tek satırlık ifadeler için kullanışlıdır:
Map.forEach'in doğrudan iki argümanlı bir lambda (key, value) aldığına dikkat et - entrySet()'e gerek yok. Hızlı yan etkiler için forEach kullan; gövde büyüdüğünde veya erken çıkmak için break gerektiğinde sıradan for döngüsüne dön, çünkü bir lambda bunu yapamaz.
Sonraki: Metotlar
Artık verileri koleksiyonlara paketledin ve onları Java'nın sunduğu her şekilde dolaştın. Bir sonraki adım davranışı paketlemektir: kendi metotlarını yazmak; böylece bir mantık bloğuna isim verebilir, ona girdiler verebilir ve onu yeniden kullanabilirsin - ki bu da sonraki sayfa.
Sıkça Sorulan Sorular
Java'da bir liste üzerinde nasıl dönülür?
En temiz yol gelişmiş for döngüsüdür (for-each): for (String s : list) { ... }. Herhangi bir Collection üzerinde çalışır - ArrayList, HashSet vb. İndeksli ve get(i) kullanan bir döngüyü yalnızca konuma gerçekten ihtiyacın olduğunda, bir Iterator'ı ise döngü sırasında eleman çıkarman gerektiğinde kullan.
Java'da bir HashMap üzerinde nasıl gezinilir?
Bir Map, Collection değildir, bu yüzden görünümlerinden biri üzerinde dönersin. Olağan tercih for (Map.Entry<K, V> e : map.entrySet())'tir; bu sana anahtarı (e.getKey()) ve değeri (e.getValue()) tek geçişte birlikte verir. Anahtarlar için map.keySet() veya değerler için map.values() üzerinde de dönebilirsin.
Gezinirken neden ConcurrentModificationException alıyorum?
Bir for-each döngüsü koleksiyonu dolaşırken koleksiyon üzerinde add veya remove çağırdın. for-each döngüsü arka planda bir Iterator kullanır ve koleksiyonun yapısal olarak değiştiğini algılar. Bunu, Iterator'ın kendi remove() metoduyla çıkararak veya döngü yerine removeIf(...) çağırarak düzelt.