Menu

Iterasi Collection Java: for-each, Iterator, forEach

Berbagai cara menelusuri collection di Java, yaitu for-each loop, Iterator, loop dengan index, dan method forEach, serta cara menghapus elemen dengan aman saat iterasi.

Halaman ini dilengkapi editor yang bisa dijalankan. Edit, jalankan, dan lihat output-nya seketika.

Satu Tugas, Beberapa Alat

Kamu sudah mengumpulkan sejumlah data, entah di ArrayList, HashSet, atau HashMap, dan sekarang kamu ingin mengunjungi setiap elemennya. Java memberimu beberapa cara untuk itu. Pilihannya bergantung pada apakah kamu butuh index, apakah kamu perlu menghapus item di tengah loop, dan apakah kamu lebih suka sintaks gaya method atau gaya loop.

Kabar baiknya: setiap Collection (list, set, queue) mendukung enhanced for loop yang sama, jadi begitu kamu mempelajarinya, kamu bisa menelusuri semuanya dengan cara yang sama.

Baca titik duanya sebagai "di dalam": "untuk setiap lang di dalam langs". Kamu tidak pernah menyentuh index, jadi tidak ada yang bisa salah.

for-each Loop

Enhanced for adalah pilihan default untuk tugas sederhana "lakukan sesuatu pada setiap elemen". Mudah dibaca dan bekerja dengan cara yang sama di semua tipe collection, di sini pada HashSet, yang sama sekali tidak punya index:

Satu hal yang perlu diingat tentang HashSet: urutannya tidak terdefinisi, jadi elemennya bisa tercetak dengan urutan apa saja. For-each tetap mengunjungi semuanya tepat satu kali.

Saat Kamu Butuh Index

For-each memberimu elemennya tetapi tidak posisinya. Kalau kamu benar-benar butuh index, misalnya untuk memberi nomor baris atau melihat elemen tetangganya, pakai loop berpenghitung dengan size() dan get(i). Cara ini bekerja pada List, yang berbasis posisi; set dan map tidak punya index, jadi gaya ini tidak berlaku untuk keduanya.

Jangan memakai cara ini hanya karena kebiasaan. Kalau kamu tidak memakai i untuk apa pun selain get(i), versi for-each lebih pendek dan lebih sulit disalahgunakan.

Iterasi pada Map

Map bukan Collection, jadi kamu tidak bisa memakai for-each langsung padanya. Sebagai gantinya, kamu menelusuri salah satu dari tiga view-nya. Yang paling umum adalah entrySet(), yang memberimu setiap pasangan key-value sekaligus:

Kalau kamu hanya butuh key-nya, telusuri ages.keySet(); kalau hanya butuh value-nya, telusuri ages.values(). Utamakan entrySet() saat kamu butuh keduanya: menelusuri key lalu memanggil ages.get(key) di dalamnya berarti melakukan pencarian kedua di setiap iterasi tanpa alasan.

Iterator

For-each sebenarnya adalah syntactic sugar di atas Iterator, yaitu objek yang menelusuri collection satu elemen demi satu elemen lewat hasNext() dan next(). Kamu jarang menulis loop ini secara manual, dengan satu pengecualian penting: inilah cara yang aman untuk menghapus elemen saat iterasi.

it.remove() menghapus elemen yang terakhir dikembalikan oleh next(), dan iterator-nya tetap valid. Inilah satu-satunya cara resmi untuk mengubah collection selama loop manual.

Jebakan: ConcurrentModificationException

Kalau kamu memanggil add atau remove pada collection itu sendiri di dalam for-each loop, kamu akan mendapat ConcurrentModificationException: iterator menyadari bahwa collection-nya berubah di tengah jalan dan menolak melanjutkan. Ini salah satu error pemula yang paling umum, dan seperti exception runtime lainnya, ia menghentikan method kecuali kamu menghindari pemicunya.

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

Solusinya hampir selalu removeIf, yang menyatakan maksudnya dalam satu baris dan mengurus iterasinya untukmu:

removeIf bekerja pada Collection apa pun, jadi pemanggilan yang sama juga bisa membersihkan HashSet.

Method forEach

Setiap collection juga punya method forEach yang menerima lambda dan menjalankannya pada setiap elemen. Ini alternatif loop yang lebih fungsional dan bergaya ekspresi, praktis untuk kode singkat satu baris:

Perhatikan bahwa Map.forEach langsung menerima lambda dua argumen (key, value), tanpa perlu entrySet(). Pakai forEach untuk efek samping yang singkat; kembali ke for loop biasa saat isi loop-nya membesar atau kamu perlu break lebih awal, yang tidak bisa dilakukan oleh lambda.

Berikutnya: Method

Sekarang kamu sudah mengemas data ke dalam collection dan menelusurinya dengan semua cara yang ditawarkan Java. Langkah berikutnya adalah mengemas perilaku: menulis method sendiri supaya kamu bisa memberi nama pada sebuah blok logika, memberinya input, dan memakainya ulang. Itu topik halaman berikutnya.

Pertanyaan yang sering diajukan

Bagaimana cara melakukan perulangan pada list di Java?

Cara paling rapi adalah enhanced for loop (for-each): for (String s : list) { ... }. Cara ini bekerja pada Collection apa pun, misalnya ArrayList, HashSet, dan seterusnya. Pakai loop dengan index dan get(i) hanya saat kamu memang butuh posisinya, dan pakai Iterator saat kamu perlu menghapus elemen di tengah loop.

Bagaimana cara melakukan iterasi pada HashMap di Java?

Map bukan Collection, jadi kamu menelusuri salah satu view-nya. Pilihan yang biasa adalah for (Map.Entry<K, V> e : map.entrySet()), yang memberimu key (e.getKey()) sekaligus value (e.getValue()) dalam satu kali penelusuran. Kamu juga bisa menelusuri map.keySet() untuk key atau map.values() untuk value.

Kenapa saya mendapat ConcurrentModificationException saat melakukan perulangan?

Kamu memanggil add atau remove pada collection saat for-each loop sedang menelusurinya. Di balik layar, for-each loop memakai Iterator, dan iterator itu mendeteksi bahwa struktur collection-nya berubah. Perbaiki dengan menghapus lewat method remove() milik Iterator itu sendiri, atau dengan memanggil removeIf(...) sebagai pengganti loop.

Ilustrasi bahasa pemrograman di Coddy

Belajar coding dengan Coddy

Mulai