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.
// 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.
// 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:
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, AndiMari kita telaah baris-baris kode di atas:
- Baris 5-7 (
fun repotimes(n: Int, aksi: (Int) -> Unit)): parameter terakhiraksiadalah function type(Int) -> Unit. Karena parameter terakhir adalah function type, kita berhak memakai trailing lambda saat memanggil. - Baris 27 (
repotimes(3, { i -> ... })): bentuk konvensional — lambda berada di dalam tanda kurung. - Baris 31 (
repotimes(3) { i -> ... }): bentuk trailing lambda — lambda ditempatkan setelah kurung tutup. Tanda kurung hanya berisi parameter non-function. - Baris 37 (
mapLalu(angka) { it * 2 }): trailing lambda denganitimplisit. Body lambda sangat singkat sehingga idiom ini terbaca natural. - Baris 42-45 (
jalankanDenganConfig("AppKu", 2) { ... }): kombinasi beberapa argumen biasa diikuti trailing lambda. Argumen non-function tetap di dalam kurung. - Baris 50 (
nama.joinToString(...) { ... }): function standard libraryjoinToStringmenerima parameter lambdatransform. 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.
| Situasi | Bisa Trailing? | Contoh |
|---|---|---|
| Function type di akhir | Ya | f(a, b, lambda) { ... } |
| Function type di tengah | Tidak | f(a, lambda, b) { ... } — salah |
| Hanya satu parameter function | Ya, kurung dihapus | f { ... } |
| Dua parameter function | Hanya yang terakhir | f({ 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.
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 #
- Higher-order functions and lambdas — panduan resmi trailing lambda di Kotlin
- Scope functions — scope function memakai pola trailing lambda
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.