when adalah salah satu konstruk paling ekspresif di Kotlin. Selain pencocokan nilai sederhana, when mendukung pencocokan tipe lewat is, pencocokan rentang lewat in, deklarasi variabel subject, dan destrukturisasi. Kompilator juga mengecek exhaustiveness untuk sealed class dan enum — bila ada variant yang tidak ditangani, kompilasi gagal. Pada chapter ini kita akan membedah fitur when tingkat lanjut yang stabil di Kotlin 2.0.21, lengkap dengan contoh untuk masing-masing pola, dan menutup dengan ringkasan kapan memakai pola mana.
Exhaustive when untuk Sealed Class #
Saat subject when adalah sealed class atau enum, kompilator mengecek bahwa semua variant ditangani. Bila ada yang terlewat, kompilasi gagal:
// when_expressions_lanjutan.kt
// Mendemonstrasikan penggunaan `when` tingkat lanjut:
// - destructuring di when-subject
// - binding variabel subject
// - sealed class dengan data class
// - range dan multiple values
// - when sebagai expression (exhaustive)
// 1. Sealed class dengan data class — `when` exhaustive
sealed interface Hasil {
data class Sukses(val data: String) : Hasil
data class Galat(val kode: Int, val pesan: String) : Hasil
data object Loading : Hasil
data object Selesai : Hasil
}
fun ringkasHasil(h: Hasil): String = when (h) {
is Hasil.Sukses -> "Sukses: ${h.data}"
is Hasil.Galat -> "Galat ${h.kode}: ${h.pesan}"
Hasil.Loading -> "Sedang loading..."
Hasil.Selesai -> "Selesai"
}
// 2. Multiple values dan range
fun kategoriNilai(n: Int): String = when (n) {
0 -> "Nol"
in 1..59 -> "Remedial"
in 60..74 -> "Cukup"
in 75..84 -> "Baik"
in 85..100 -> "Sangat Baik"
else -> "Di luar jangkauan"
}
// 3. Pair destructuring (via when subject)
fun prosesPair(p: Pair<String, Int>): String {
val (nama, umur) = p
return when {
umur < 17 -> "$nama belum dewasa (umur $umur)"
umur in 17..60 -> "$nama usia produktif (umur $umur)"
else -> "$nama senior (umur $umur)"
}
}
// 4. when dengan binding variabel subject (`when (val x = ...)`)
fun parseDanKlasifikasi(input: String): String {
return when (val angka = input.toIntOrNull()) {
null -> "Input bukan bilangan"
0 -> "Nol"
in 1..9 -> "Satuan: $angka"
in 10..99 -> "Puluhan: $angka"
else -> "Besar: $angka"
}
}
// 5. when tanpa subject (chain of boolean)
fun musim(bulan: Int): String = when {
bulan in 1..3 -> "Hujan"
bulan in 4..6 -> "Pancaroba"
bulan in 7..9 -> "Kemarau"
bulan in 10..12 -> "Pancaroba"
else -> "Bulan tidak valid"
}
fun main() {
println("=== 1. Sealed class exhaustive when ===")
val daftar: List<Hasil> = listOf(
Hasil.Loading,
Hasil.Sukses("data pengguna"),
Hasil.Galat(404, "tidak ditemukan"),
Hasil.Selesai
)
daftar.forEach { println(" ${ringkasHasil(it)}") }
println()
println("=== 2. Range dan multiple values ===")
listOf(0, 45, 70, 80, 95, 150).forEach {
println(" $it -> ${kategoriNilai(it)}")
}
println()
println("=== 3. Pair destructuring ===")
println(prosesPair("Budi" to 12))
println(prosesPair("Siti" to 30))
println(prosesPair("Dewi" to 70))
println()
println("=== 4. when dengan binding variabel subject ===")
listOf("42", "0", "8", "75", "halo").forEach {
println(" \"$it\" -> ${parseDanKlasifikasi(it)}")
}
println()
println("=== 5. when tanpa subject ===")
(1..12).forEach { println(" bulan $it -> ${musim(it)}") }
println()
println("=== 6. Ringkasan ===")
val ringkasan = listOf(
"when(subject) - cocok nilai/instance",
"in range - cek angka dalam rentang",
"is Type - smart cast ke tipe tersebut",
"binding val x = ... - simpan subject di variabel",
"when {} tanpa subject - rangkaian boolean"
)
ringkasan.forEach { println(" - $it") }
}Output yang Dihasilkan:
=== 1. Sealed class exhaustive when ===
Sedang loading...
Sukses: data pengguna
Galat 404: tidak ditemukan
Selesai
=== 2. Range dan multiple values ===
0 -> Nol
45 -> Remedial
70 -> Cukup
80 -> Baik
95 -> Sangat Baik
150 -> Di luar jangkauan
=== 3. Pair destructuring ===
Budi belum dewasa (umur 12)
Siti usia produktif (umur 30)
Dewi senior (umur 70)
=== 4. when dengan binding variabel subject ===
"42" -> Puluhan: 42
"0" -> Nol
"8" -> Satuan: 8
"75" -> Puluhan: 75
"halo" -> Input bukan bilangan
=== 5. when tanpa subject ===
bulan 1 -> Hujan
bulan 2 -> Hujan
bulan 3 -> Hujan
bulan 4 -> Pancaroba
bulan 5 -> Pancaroba
bulan 6 -> Pancaroba
bulan 7 -> Kemarau
bulan 8 -> Kemarau
bulan 9 -> Kemarau
bulan 10 -> Pancaroba
bulan 11 -> Pancaroba
bulan 12 -> Pancaroba
=== 6. Ringkasan ===
- when(subject) - cocok nilai/instance
- in range - cek angka dalam rentang
- is Type - smart cast ke tipe tersebut
- binding val x = ... - simpan subject di variabel
- when {} tanpa subject - rangkaian booleanPada cuplikan di atas, when (h) menangani semua empat variant dari sealed interface Hasil. Smart cast bekerja otomatis — setelah is Hasil.Sukses, kita bisa langsung memanggil h.data tanpa cast eksplisit. Bila kita menambahkan variant baru (mis. data object Dibatalkan), kompilator akan menolak when yang lama hingga kita menambahkan branch baru.
Range dan Multiple Values #
when mendukung pencocokan rentang dengan in:
fun kategoriNilai(n: Int): String = when (n) {
0 -> "Nol"
in 1..59 -> "Remedial"
in 60..74 -> "Cukup"
in 75..84 -> "Baik"
in 85..100 -> "Sangat Baik"
else -> "Di luar jangkauan"
}Untuk pencocokan beberapa nilai diskrit (mis. 1, 3, 5), kita bisa menulis 1, 3, 5 -> di satu branch. Rentang cocok untuk skenario seperti kategori nilai atau kode HTTP, sementara multiple values cocok untuk enum subset.
Binding Variabel Subject #
Kita bisa mendeklarasikan variabel subject di dalam when agar bisa dipakai di seluruh branch:
fun parseDanKlasifikasi(input: String): String {
return when (val angka = input.toIntOrNull()) {
null -> "Input bukan bilangan"
0 -> "Nol"
in 1..9 -> "Satuan: $angka"
in 10..99 -> "Puluhan: $angka"
else -> "Besar: $angka"
}
}Pola ini sangat berguna saat hasil ekspresi butuh dipakai beberapa kali di cabang yang berbeda — variabel angka tetap berlaku di seluruh branch.
when Tanpa Subject #
Untuk rangkaian kondisi boolean yang berbeda-beda, kita bisa memakai when tanpa subject:
fun musim(bulan: Int): String = when {
bulan in 1..3 -> "Hujan"
bulan in 4..6 -> "Pancaroba"
bulan in 7..9 -> "Kemarau"
bulan in 10..12 -> "Pancaroba"
else -> "Bulan tidak valid"
}Pola ini mirip if-else-if tetapi lebih rapi. Branch pertama yang mengembalikan true akan dipilih.
Destructuring Pair dan Data Class #
Kombinasi when dengan destrukturisasi Pair atau data class membuat kode yang memproses tuple menjadi lebih ringkas:
fun prosesPair(p: Pair<String, Int>): String {
val (nama, umur) = p
return when {
umur < 17 -> "$nama belum dewasa (umur $umur)"
umur in 17..60 -> "$nama usia produktif (umur $umur)"
else -> "$nama senior (umur $umur)"
}
}Kita bisa menulis val (nama, umur) = p di luar when dan memakai nilai tersebut di seluruh branch. Untuk lambda, Kotlin mendukung destrukturisasi otomatis lewat sintaks { (a, b) -> ... }.
Ringkasan Pola #
Tabel berikut merangkum pola when yang paling sering dipakai:
| Pola | Sintaks | Kapan dipakai |
|---|---|---|
| Pencocokan nilai | when (x) { 1 -> ...; 2 -> ... } | Switch sederhana |
| Pencocokan tipe | when (x) { is String -> ... } | Type dispatch, polymorphism |
| Pencocokan rentang | when (n) { in 1..10 -> ... } | Kategori berbasis rentang |
| Multiple values | when (n) { 1, 3, 5 -> ... } | Subset enum / konstanta diskrit |
| Binding subject | when (val x = ...) { ... } | Hasil ekspresi butuh dipakai ulang |
| Tanpa subject | when { cond1 -> ...; cond2 -> ... } | Rangkaian boolean berbeda-beda |
Referensi Lanjutan #
- What’s new in Kotlin 2.0
— ringkasan Kotlin 2.0 yang mencatat penyempurnaan
whenexpressions termasuk subject binding dan guard - Kotlin documentation home
— halaman utama dokumentasi Kotlin sebagai pintu masuk panduan
whenexpressions modern
Selanjutnya #
Setelah menguasai when lanjutan, kita lanjut ke fitur tipe lanjutan — definitely non-nullable types (T & Any) — yang memaksa tipe parameter generik non-nullable di scope tertentu.