Kotlin menyediakan ratusan operasi siap pakai pada Iterable<T>. Operasi ini memungkinkan kita memanipulasi collection dengan gaya deklaratif — menyatakan apa yang ingin kita capai, bukan bagaimana melakukannya. Pada chapter ini kita akan mempelajari operasi paling sering dipakai: forEach, map, filter, find, any, all, none, dan count. Penguasaan operasi ini menjadi pondasi untuk operasi yang lebih kompleks seperti flatMap, groupBy, dan reduce.
forEach: Iterasi Tanpa Return #
forEach menerima lambda (T) -> Unit dan menjalankannya sekali per elemen. Hasilnya Unit, sehingga tidak ada nilai kembalian — operasi ini dipakai untuk efek samping seperti mencetak atau mengakumulasi nilai ke variabel luar.
listOf(1, 2, 3).forEach { println(it) }Parameter it adalah nama implisit untuk elemen yang sedang diiterasi.
map: Transformasi #
map { it -> ... } mengembalikan collection baru yang berisi hasil transformasi tiap elemen. Panjang hasil sama dengan panjang input.
val angka = listOf(1, 2, 3)
val kuadrat = angka.map { it * it } // [1, 4, 9]
val panjang = angka.map { "Angka $it".length }filter: Seleksi #
filter { predicate } mengembalikan collection baru yang hanya berisi elemen yang memenuhi predikat. Lambda harus mengembalikan Boolean.
val angka = listOf(1, 2, 3, 4, 5)
val genap = angka.filter { it % 2 == 0 } // [2, 4]
val besar = angka.filter { it > 3 } // [4, 5]find, any, all, none, count #
Operasi ini menghasilkan jawaban atas pertanyaan spesifik tanpa harus menulis loop manual:
| Operasi | Mengembalikan | Kapan dipakai |
|---|---|---|
find { pred } | Elemen pertama yang cocok atau null | Mencari satu elemen |
any { pred } | Boolean, true jika ada elemen yang cocok | Cek keberadaan |
all { pred } | Boolean, true jika semua elemen cocok | Cek keseluruhan |
none { pred } | Boolean, true jika tidak ada yang cocok | Cek ketiadaan |
count { pred } | Int, jumlah elemen yang cocok | Menghitung jumlah |
Tanpa predikat, any(), all(), none() menggunakan keberadaan elemen. count() tanpa argumen sama dengan size.
Contoh Lengkap #
fun main() {
val nilai = listOf(75, 60, 90, 45, 80, 55, 95)
// forEach: iterasi tanpa return
print("Semua nilai: ")
nilai.forEach { print("$it ") }
println()
// map: transformasi tiap elemen
val skalaSeratus = nilai.map { it / 100.0 }
println("Skala 0..1: $skalaSeratus")
// filter: pertahankan elemen yang memenuhi kondisi
val lulus = nilai.filter { it >= 70 }
println("Lulus (>=70): $lulus")
// find: elemen pertama yang cocok, atau null
val pertamaLulus = nilai.find { it >= 70 }
println("Pertama lulus: $pertamaLulus")
val tidakAda = nilai.find { it > 100 }
println("Pertama >100: $tidakAda")
// any, all, none: boolean predikat
println("Ada yang >=90? ${nilai.any { it >= 90 }}")
println("Semua >=40? ${nilai.all { it >= 40 }}")
println("Tidak ada <40? ${nilai.none { it < 40 }}")
// count: jumlah elemen yang memenuhi predikat
println("Jumlah lulus: ${nilai.count { it >= 70 }}")
println("Total elemen: ${nilai.count()}")
// filter + find + count bergabung
val lulusBaik = nilai.filter { it >= 80 }
println("Lulus baik (>=80): $lulusBaik")
println("Jumlah lulus baik: ${lulusBaik.count()}")
// Penggunaan together: chaining
val ringkasan = nilai
.filter { it >= 60 }
.map { if (it >= 80) "A" else if (it >= 70) "B" else "C" }
println("Grade (filter lalu map): $ringkasan")
// any dengan predikat berat
val adaNilaiSempurna = nilai.any { it == 100 }
println("Ada nilai 100? $adaNilaiSempurna")
}Output yang Dihasilkan:
Semua nilai: 75 60 90 45 80 55 95
Skala 0..1: [0.75, 0.6, 0.9, 0.45, 0.8, 0.55, 0.95]
Lulus (>=70): [75, 90, 80, 95]
Pertama lulus: 75
Pertama >100: null
Ada yang >=90? true
Semua >=40? true
Tidak ada <40? true
Jumlah lulus: 4
Total elemen: 7
Lulus baik (>=80): [90, 80, 95]
Jumlah lulus baik: 3
Grade (filter lalu map): [B, C, A, A, A]
Ada nilai 100? falseMari kita bedah baris-baris penting di atas:
nilai.forEach { print("$it ") }: lambda dijalankan sekali per elemen.itmerujuk ke elemen saat ini. Tidak ada nilai kembalian sehingga cocok untuk efek samping seperti mencetak.nilai.map { it / 100.0 }: tiapIntdibagi100.0, menghasilkanDouble. Karena pembagian mengandungDouble, hasilnya jugaDouble. Panjang list tetap 7.nilai.filter { it >= 70 }: hanya elemen>= 70yang dipertahankan. Hasilnya[75, 90, 80, 95]— urutan relatif elemen tetap.nilai.find { it >= 70 }: mengembalikan elemen pertama yang memenuhi predikat (75). Bila tidak ada, hasilnyanull. Nama lainnya adalahfirstOrNull { ... }.nilai.any { it >= 90 }: berhenti begitu menemukan elemen yang cocok (short-circuit). Tidak perlu mengiterasi seluruh list bila jawaban sudah jelastrue.nilai.none { it < 40 }: ekuivalen dengan!any { it < 40 }. Mengembalikantruekarena tidak ada nilai di bawah 40.nilai.count { it >= 70 }: menghitung jumlah elemen yang memenuhi predikat. Lebih efisien daripadanilai.filter { it >= 70 }.sizekarena tidak mengalokasikan list baru.
Chaining Operasi #
Operasi-operasi di atas dapat dirangkai menjadi pipeline. Hasil satu operasi menjadi input operasi berikutnya:
val ringkasan = nilai
.filter { it >= 60 } // sisakan yang >= 60
.map { if (it >= 80) "A" else if (it >= 70) "B" else "C" } // ubah jadi grade
.sortedByDescending { it.first() } // urut descendingPipeline ini terbaca sebagai kalimat: “Ambil nilai, saring yang >= 60, petakan jadi grade, lalu urutkan.” Gaya deklaratif ini adalah inti dari pemrograman fungsional yang didukung Kotlin.
Referensi Lanjutan #
- Collection operations overview
— panduan resmi
map,filter,find, dan operator+/- - Collections overview — tinjauan umum operasi collection
Dengan pondasi map, filter, dan find di tangan, kita siap mengeksplorasi varian-varian filter yang lebih kaya pada chapter berikutnya.