Scope function let adalah salah satu alat paling serbaguna untuk penanganan nullable di Kotlin. Dipadukan dengan operator safe call ?., blok let hanya dieksekusi bila penerima tidak null, dan parameter it di dalam blok sudah bertipe non-nullable. Pola ini menjadi alternatif ringkas untuk if (x != null) { ... } dan sangat berguna saat kita perlu menjalankan beberapa statement terhadap nilai nullable. Pada chapter ini kita akan membedah cara kerja ?.let, parameter it, serta perbandingannya dengan pola if eksplisit.
Cara Kerja ?.let #
let adalah function ekstensi pada tipe T yang menerima lambda (T) -> R dan mengembalikan hasil lambda. Bentuk umum: penerima?.let { it -> ... }. Bila penerima null, blok let tidak dieksekusi dan seluruh ekspresi menghasilkan null. Bila tidak null, let dipanggil dengan parameter it bertipe non-nullable.
data class Pengguna(val nama: String, val email: String?)
fun main() {
val nama1: String? = "Budi"
nama1?.let {
println("Memproses nama: $it")
println("Panjang nama: ${it.length}")
println("Huruf besar: ${it.uppercase()}")
}
val nama2: String? = null
nama2?.let {
println("Ini tidak akan tercetak: $it")
}
println("nama2 null, blok let dilewati")
val pengguna: Pengguna? = Pengguna("Siti", "[email protected]")
pengguna?.email?.let { alamatEmail ->
println("Email: $alamatEmail")
println("Domain: ${alamatEmail.substringAfter('@')}")
}
val penggunaLain: Pengguna? = Pengguna("Dewi", null)
penggunaLain?.email?.let { alamatEmail ->
println("Email Dewi: $alamatEmail")
}
println("Selesai memeriksa email Dewi")
val daftar: List<String?> = listOf("Budi", null, "Siti", null, "Dewi")
for (item in daftar) {
item?.let { namaValid ->
println("Nama valid ditemukan: $namaValid (panjang ${namaValid.length})")
}
}
val idPengguna: Long? = 9988L
val idFormatted: String = idPengguna?.let { "ID-$it" } ?: "TANPA-ID"
println("ID terformat: $idFormatted")
val konfigurasi: Map<String, String?> = mapOf("host" to "localhost", "port" to null)
val port: Int = konfigurasi["port"]?.let { it.toIntOrNull() ?: 8080 } ?: 8080
println("Port akhir: $port")
val nilai: String? = "Belajar"
nilai?.let { namaLengkap ->
val panjang = namaLengkap.length
val hurufKapital = namaLengkap.uppercase()
println("Panjang=$panjang, kapital=$hurufKapital")
}
val opsional: String? = null
val hasil: Int = opsional?.let { it.length } ?: 0
println("Hasil panjang (default 0): $hasil")
}Output yang Dihasilkan:
Memproses nama: Budi
Panjang nama: 4
Huruf besar: BUDI
nama2 null, blok let dilewati
Email: [email protected]
Domain: example.com
Selesai memeriksa email Dewi
Nama valid ditemukan: Budi (panjang 4)
Nama valid ditemukan: Siti (panjang 4)
Nama valid ditemukan: Dewi (panjang 4)
ID terformat: ID-9988
Port akhir: 8080
Panjang=7, kapital=BELAJAR
Hasil panjang (default 0): 0Mari kita uraikan baris-baris penting pada contoh di atas:
- Baris 5-9 (
nama1?.let { ... }): pola paling dasar.nama1tidak null sehingga blokletdijalankan. ParameteritbertipeString(non-nullable), sehingga.lengthdan.uppercase()dapat dipanggil langsung. - Baris 11-13 (
nama2?.let { ... }):nama2adalahnull, sehingga bloklettidak dieksekusi sama sekali. Tidak ada pengecualian yang dilempar. - Baris 16-19 (
pengguna?.email?.let { alamatEmail -> ... }): safe call dirantaikan denganlet. Parameter diganti nama menjadialamatEmailagar lebih deskriptif. Penggantian nama sangat berguna bilaitterlalu generik untuk konteks blok. - Baris 21-24 (
penggunaLain?.email?.let { ... }): kasus di manapenggunaLaintidak null namunemailnull. Rantai safe call?.menjamin blokletdilewati secara halus. - Baris 28-32 (iterasi
for (item in daftar)):?.letpada iterasi elemen nullable. Untuk setiap elemen non-null, blok dijalankan; elemen null diam-diam dilewati tanpa perluifeksplisit. - Baris 35 (
idPengguna?.let { "ID-$it" } ?: "TANPA-ID"): kombinasi?.letdengan Elvis. BlokletmengembalikanStringformatted, dan Elvis memberi nilai default bilaidPenggunanull. - Baris 38 (
konfigurasi["port"]?.let { it.toIntOrNull() ?: 8080 } ?: 8080): pola defensive parsing. Bilaportnull, Elvis luar memberi8080. Bilaportada namun bukan angka valid,toIntOrNull()mengembalikan null dan Elvis dalam memberi8080. Lapis ganda untuk keamanan maksimal. - Baris 47 (
hasil: Int = opsional?.let { it.length } ?: 0):?.letmengembalikan nilai terakhir lambda sebagai hasil ekspresi. Hasil ini masih bertipeInt?karena blok hanya berjalan bilaopsionaltidak null. Elvis luar mengubahnya menjadiIntnon-nullable.
Perbandingan dengan if (x != null) #
Bentuk ?.let dan if (x != null) sering kali dapat dipertukarkan. Pilihan antara keduanya biasanya didasarkan pada gaya dan konteks:
| Aspek | ?.let { ... } | if (x != null) { ... } |
|---|---|---|
| Sintaks | Ekspresi nilai (lambda) | Statement blok |
| Smart cast | Parameter it non-nullable | Variabel asli di-smart-cast |
| Mengembalikan nilai | Ya, hasil lambda | Hanya jika if dipakai sebagai ekspresi |
| Cocok untuk | Transformasi ringkas, chain | Beberapa statement sekuensial |
| Pengganti nama | Mudah via nama -> | Tidak, tetap memakai variabel asli |
Mengganti Nama Parameter it #
Saat blok let berisi beberapa baris atau saat konteks sudah punya variabel dengan nama serupa, parameter default it bisa jadi membingungkan. Kotlin memungkinkan kita memberi nama eksplisit pada parameter lambda dengan pola ?.let { nama -> ... }. Pemberian nama eksplisit membuat kode lebih mudah dibaca terutama saat blok cukup panjang atau saat it berpotensi tertukar dengan variabel lain di luar.
Pemilihan nama parameter sebaiknya mendeskripsikan peran nilai, bukan tipenya. Nama seperti pengguna, alamatEmail, atau idValid lebih informatif daripada it atau value. Konvensi ini sejalan dengan praktik penamaan variabel pada umumnya — tujuan utamanya adalah agar pembaca kode dapat memahami maksud tanpa harus melihat-lihat konteks di sekitarnya.
Saat Tidak Perlu Memakai ?.let #
Beberapa situasi tidak memerlukan ?.let dan sebaiknya memakai alternatif yang lebih ringkas. Bila tujuan hanya mengembalikan nilai default saat null, operator Elvis ?: lebih singkat dan langsung. Bila tujuan hanya memfilter elemen non-null pada koleksi, filterNotNull() lebih ekspresif. Bila kita perlu memanggil beberapa method pada objek non-nullable hasil smart cast, if (x != null) { ... } sering lebih jelas daripada ?.let karena smart cast bekerja langsung tanpa perlu parameter it.
Referensi Lanjutan #
- Null-safety
— bagian
letuntuk null handling pada panduan null-safety resmi
Setelah memahami let, langkah berikutnya adalah mengenal platform types — situasi khusus yang muncul saat kode Kotlin memanggil kode Java di mana informasi nullability tidak tersedia — topik yang akan kita bahas pada chapter Platform Types.