Idiom trailing lambda adalah salah satu ciri khas Kotlin yang membuat kode terbaca seperti kalimat natural. Ketika parameter terakhir sebuah function adalah function type, Kotlin mengizinkan kita menulis lambda di luar tanda kurung — bahkan menghapus tanda kurung sama sekali bila tidak ada parameter lain. Pada chapter ini kita akan melihat konsep trailing lambda, kapan dapat dipakai, dan mengapa idiom ini menjadi standar de facto di standard library Kotlin. Kita juga akan membandingkan bentuk dalam-kurung vs trailing lambda pada contoh nyata.

Apa Itu Trailing Lambda #

Trailing lambda adalah sintaks khusus yang berlaku ketika parameter terakhir sebuah function adalah function type. Pada situasi ini, lambda dapat ditempatkan di luar tanda kurung pemanggilan function. Bila function hanya memiliki satu parameter dan parameter tersebut adalah function type, tanda kurung dapat dihilangkan seluruhnya.

kotlin Bentuk umum trailing lambda
// Dengan tanda kurung
repeat(3, { println("Halo") })

// Trailing lambda
repeat(3) { println("Halo") }

Kedua bentuk di atas identik secara semantik; trailing lambda hanya variasi sintaks yang lebih ringkas dan lebih mudah dibaca.

Contoh Trailing Lambda #

Mari kita lihat trailing lambda dalam berbagai situasi — function buatan sendiri dan function standard library.

kotlin
// trailing_lambdas.kt
// Trailing lambda: lambda diletakkan di luar tanda kurung parameter.

// Higher-order function sederhana untuk demonstrasi.
fun repotimes(n: Int, aksi: (Int) -> Unit) {
    for (i in 0 until n) aksi(i)
}

fun <T, R> mapLalu(daftar: List<T>, transform: (T) -> R): List<R> {
    val hasil = mutableListOf<R>()
    for (e in daftar) hasil.add(transform(e))
    return hasil
}

fun jalankanDenganConfig(
    nama: String,
    versi: Int,
    config: () -> Unit
) {
    println("Menjalankan $nama v$versi")
    config()
}

fun main() {
    // Panggilan biasa: lambda di dalam kurung.
    repotimes(3, { i -> println("  iterasi $i (dalam kurung)") })

    // Trailing lambda: lambda di luar kurung.
    repotimes(3) { i ->
        println("  iterasi $i (trailing)")
    }

    // Trailing lambda dengan mapLalu.
    val angka = listOf(1, 2, 3, 4, 5)
    val doubled = mapLalu(angka) { it * 2 }
    println("Doubled: $doubled")

    // Kombinasi argumen biasa + trailing lambda.
    jalankanDenganConfig("AppKu", 2) {
        println("  konfigurasi tambahan dimuat")
        println("  cache dipanaskan")
    }

    // Standard library menggunakan trailing lambda di banyak tempat.
    val nama = listOf("budi", "siti", "andi")
    val namaKapital = nama.joinToString(separator = ", ") { it.replaceFirstChar { c -> c.uppercase() } }
    println("Nama kapital: $namaKapital")
}

Output yang Dihasilkan:

text
  iterasi 0 (dalam kurung)
  iterasi 1 (dalam kurung)
  iterasi 2 (dalam kurung)
  iterasi 0 (trailing)
  iterasi 1 (trailing)
  iterasi 2 (trailing)
Doubled: [2, 4, 6, 8, 10]
Menjalankan AppKu v2
  konfigurasi tambahan dimuat
  cache dipanaskan
Nama kapital: Budi, Siti, Andi

Mari kita telaah baris-baris kode di atas:

  1. Baris 5-7 (fun repotimes(n: Int, aksi: (Int) -> Unit)): parameter terakhir aksi adalah function type (Int) -> Unit. Karena parameter terakhir adalah function type, kita berhak memakai trailing lambda saat memanggil.
  2. Baris 27 (repotimes(3, { i -> ... })): bentuk konvensional — lambda berada di dalam tanda kurung.
  3. Baris 31 (repotimes(3) { i -> ... }): bentuk trailing lambda — lambda ditempatkan setelah kurung tutup. Tanda kurung hanya berisi parameter non-function.
  4. Baris 37 (mapLalu(angka) { it * 2 }): trailing lambda dengan it implisit. Body lambda sangat singkat sehingga idiom ini terbaca natural.
  5. Baris 42-45 (jalankanDenganConfig("AppKu", 2) { ... }): kombinasi beberapa argumen biasa diikuti trailing lambda. Argumen non-function tetap di dalam kurung.
  6. Baris 50 (nama.joinToString(...) { ... }): function standard library joinToString menerima parameter lambda transform. Trailing lambda di sini mengubah setiap elemen string sebelum digabung.

Kapan Trailing Lambda Bisa Dipakai #

Trailing lambda hanya berlaku bila parameter terakhir function adalah function type. Bila ada function type di tengah daftar parameter, lambda tidak bisa dipindahkan ke luar.

SituasiBisa Trailing?Contoh
Function type di akhirYaf(a, b, lambda) { ... }
Function type di tengahTidakf(a, lambda, b) { ... } — salah
Hanya satu parameter functionYa, kurung dihapusf { ... }
Dua parameter functionHanya yang terakhirf({ g() }) { h() }

Trailing Lambda Bertingkat #

Saat function menerima lebih dari satu lambda, hanya yang terakhir yang dapat menjadi trailing lambda. Lambda sebelumnya tetap ditulis di dalam tanda kurung. Hal ini menjaga keterbacaan — bila dua lambda keduanya trailing, kode akan rancu.

kotlin Dua lambda, hanya satu trailing
fun proses(data: List<Int>, onEach: (Int) -> Unit, onDone: () -> Unit) {
    for (e in data) onEach(e)
    onDone()
}

proses(listOf(1, 2, 3), { println("elemen $it") }) {
    println("Selesai")
}

Mengapa Trailing Lambda Penting #

Trailing lambda membentuk gaya penulisan yang khas Kotlin. Banyak DSL dan library populer seperti Ktor, Gradle Kotlin DSL, dan Jetpack Compose memanfaatkan trailing lambda untuk membuat kode terbaca seperti blok konfigurasi, bukan pemanggilan function bertingkat. Tanpa trailing lambda, kode DSL akan terlihat berantakan dengan tanda kurung bersarang.

Referensi Lanjutan #

Penutup #

Trailing lambda adalah sentuhan sintaks yang membuat kode Kotlin terasa ringkas dan ekspresif. Dengan aturan sederhana “parameter terakhir function type”, kita dapat menulis transformasi koleksi dan blok konfigurasi tanpa tanda kurung berlebih. Selanjutnya, kita akan mempelajari it — parameter implisit yang membuat lambda satu parameter menjadi lebih ringkas lagi.