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.

kotlin Contoh: forEach
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.

kotlin Contoh: map
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.

kotlin Contoh: filter
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:

OperasiMengembalikanKapan dipakai
find { pred }Elemen pertama yang cocok atau nullMencari satu elemen
any { pred }Boolean, true jika ada elemen yang cocokCek keberadaan
all { pred }Boolean, true jika semua elemen cocokCek keseluruhan
none { pred }Boolean, true jika tidak ada yang cocokCek ketiadaan
count { pred }Int, jumlah elemen yang cocokMenghitung jumlah

Tanpa predikat, any(), all(), none() menggunakan keberadaan elemen. count() tanpa argumen sama dengan size.

Contoh Lengkap #

kotlin
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:

text
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? false

Mari kita bedah baris-baris penting di atas:

  1. nilai.forEach { print("$it ") }: lambda dijalankan sekali per elemen. it merujuk ke elemen saat ini. Tidak ada nilai kembalian sehingga cocok untuk efek samping seperti mencetak.
  2. nilai.map { it / 100.0 }: tiap Int dibagi 100.0, menghasilkan Double. Karena pembagian mengandung Double, hasilnya juga Double. Panjang list tetap 7.
  3. nilai.filter { it >= 70 }: hanya elemen >= 70 yang dipertahankan. Hasilnya [75, 90, 80, 95] — urutan relatif elemen tetap.
  4. nilai.find { it >= 70 }: mengembalikan elemen pertama yang memenuhi predikat (75). Bila tidak ada, hasilnya null. Nama lainnya adalah firstOrNull { ... }.
  5. nilai.any { it >= 90 }: berhenti begitu menemukan elemen yang cocok (short-circuit). Tidak perlu mengiterasi seluruh list bila jawaban sudah jelas true.
  6. nilai.none { it < 40 }: ekuivalen dengan !any { it < 40 }. Mengembalikan true karena tidak ada nilai di bawah 40.
  7. nilai.count { it >= 70 }: menghitung jumlah elemen yang memenuhi predikat. Lebih efisien daripada nilai.filter { it >= 70 }.size karena tidak mengalokasikan list baru.

Chaining Operasi #

Operasi-operasi di atas dapat dirangkai menjadi pipeline. Hasil satu operasi menjadi input operasi berikutnya:

kotlin Contoh: chaining
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 descending

Pipeline 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 #

Dengan pondasi map, filter, dan find di tangan, kita siap mengeksplorasi varian-varian filter yang lebih kaya pada chapter berikutnya.