when

Percabangan when sebagai pengganti switch beserta pencocokan range dan tipe.

Daftar isi

Percabangan when memilih satu cabang dari banyak pilihan, baik berdasarkan nilai, range, tipe, maupun kondisi bebas. Pada Java, kebutuhan serupa dilayani pernyataan switch, sedangkan when lebih lentur karena cabangnya dapat mencocokkan lebih dari sekadar konstanta. Topik ini membahas when atas satu nilai, atas range, atas tipe dengan Any, serta bentuk tanpa subjek. Sebuah program contoh memuat keempat bentuk tersebut dan dijalankan dengan kotlinc agar keluarannya dapat direproduksi.

when atas satu nilai#

Subjek pada when adalah nilai yang dicocokkan, ditulis di dalam kurung setelah kata kunci. Setiap cabang berupa pola, tanda ->, lalu hasilnya. Cabang pertama yang polanya cocok dipilih, dan cabang setelahnya tidak diperiksa lagi. Cabang else menampung semua nilai yang tidak tercantum, sehingga perannya sama dengan default pada switch. Subjek hanya dievaluasi satu kali, sehingga pemanggilan fungsi sebagai subjek tetap aman dilakukan. Hasil setiap cabang boleh berupa blok yang memuat beberapa pernyataan, dan nilai terakhir blok itulah yang menjadi hasil ketika when dipakai sebagai ekspresi. Berbeda dari switch pada Java, eksekusi berhenti begitu cabang yang cocok selesai, sehingga tidak ada mekanisme fallthrough yang lupa ditutup break.

kotlin Contoh: beberapa nilai dalam satu cabang
// tidak-dijalankan
when (hari) {
    6, 7 -> println("akhir pekan")
    in 1..5 -> println("hari kerja")
}

Beberapa nilai yang diperlakukan sama ditulis berdampingan dan dipisah koma, seperti 6, 7 pada contoh di atas. Cabang in 1..5 menunjukkan bahwa satu when boleh mencampur pencocokan nilai dan pencocokan range dalam satu deklarasi. Karena contoh tersebut dipakai sebagai pernyataan, cabang else boleh ditiadakan. Aturan lengkapnya dibahas pada bagian Kesalahan umum.

when atas range#

Range pada Kotlin adalah rentang nilai yang dibuat dengan operator .., misalnya 85..100. Pencocokan in 85..100 menghasilkan true apabila nilai berada di dalam rentang tersebut, termasuk kedua ujungnya. Bentuk ini menggantikan rantai perbandingan yang panjang dan membuat setiap rentang terbaca sebagai satu cabang.

Konversi nilai ujian menjadi predikat adalah contoh yang lazim. Rentang ditulis dari yang tertinggi ke terendah agar pemeriksaan berhenti pada rentang pertama yang memuat nilai. Cabang else menampung nilai di bawah 60, sehingga tidak ada nilai yang lolos tanpa predikat. Rentang pada contoh tidak tumpang tindih, tetapi when tidak menuntut hal itu. Bila dua rentang sama-sama memuat sebuah nilai, cabang yang ditulis lebih dahulu yang menang, sehingga urutan penulisan tetap perlu dijaga dengan sengaja.

Perhatikan pula bahwa rentang 85..100 mencakup angka 85 dan 100. Ujung rentang yang tertukar, misalnya in 100..85, menghasilkan rentang kosong sehingga cabang tidak pernah cocok. Kesalahan semacam ini tidak ditolak compiler karena sintaksnya sah, tetapi perilakunya diam-diam salah. Menuliskan rentang dengan urutan naik menghindarkan dari jebakan ini.

when atas tipe dengan is#

Kata kunci is mencocokkan tipe nilai, bukan nilainya. Bentuk ini berguna ketika data datang sebagai tipe umum, misalnya Any, yaitu induk semua tipe non-nullable. Cabang yang cocok memperoleh smart cast, yaitu perlakuan tipe otomatis pada lingkup cabang tersebut, sehingga anggota khusus tipe tujuan dapat dipanggil tanpa pemeriksaan tambahan.

kotlin Contoh: smart cast pada cabang is
// tidak-dijalankan
when (data) {
    is String -> println("panjang teks: ${data.length}")
    is Int -> println("bilangan bulat: $data")
}

Pada cabang pertama, data otomatis diperlakukan sebagai String, sehingga properti length dapat diakses langsung. Pada cabang kedua, data diperlakukan sebagai Int dan dapat langsung disisipkan ke dalam string template. Pencocokan tipe seperti ini menjadi fondasi ketika satu nilai dapat berupa lebih dari satu tipe. Kebalikannya ditulis !is, yaitu cabang yang dipilih bila tipe bukan yang disebutkan. Pemeriksaan tipe satu per satu dengan if juga sah, tetapi when menyatukan seluruh pilihan dalam satu deklarasi sehingga urutan dan kelengkapannya terbaca sekaligus. Selama subjek bertipe umum seperti Any, cabang else tetap diperlukan karena daftar tipe yang tercantum tidak menutup semua kemungkinan.

when tanpa subjek#

when tidak wajib memiliki subjek. Tanpa subjek, setiap cabang berupa ekspresi Boolean, dan cabang pertama yang bernilai true dipilih. Bentuk ini menyaingi rantai else if dan sering lebih rapi karena tanda -> memisahkan setiap kondisi dari hasilnya secara sejajar.

Contoh penerapannya adalah mengelompokkan suhu menjadi panas, normal, dan dingin. Kondisi ditulis dari batas yang paling tinggi ke paling rendah sehingga pemeriksaan berhenti pada kondisi pertama yang terpenuhi. Cabang else tetap diperlukan apabila when dipakai sebagai ekspresi, karena tidak ada kondisi yang menjamin true di semua kasus. Bentuk ini juga tepat ketika kondisi-cabang tidak berbagi subjek yang sama, misalnya memeriksa dua variabel berbeda dalam satu rangkaian pilihan. Kondisi pada setiap cabang tidak wajib berhubungan satu sama lain, tetapi menjaga kesatuan tema membuat percabangan tetap mudah diikuti.

Program contoh: keempat bentuk when dalam satu berkas#

Berkas main.kt berikut memuat keempat bentuk when sekaligus, yaitu when atas nilai untuk nama hari, when atas range untuk predikat, when atas tipe dengan Any, dan when tanpa subjek untuk suhu. Setiap bentuk dipisahkan komentar agar mudah dicocokkan dengan bagian sebelumnya. Untuk mereproduksi keluarannya, salin isi berkas ke sebuah direktori kerja, jalankan blok perintah di bawah, lalu bandingkan hasilnya. Tidak ada input dan argumen yang diperlukan, sehingga keluaran yang muncul sama setiap kali program dijalankan.

kotlin main.kt
fun main() {
    // when atas satu nilai
    val hari = 3
    val namaHari = when (hari) {
        1 -> "Senin"
        2 -> "Selasa"
        3 -> "Rabu"
        4 -> "Kamis"
        5 -> "Jumat"
        6, 7 -> "akhir pekan"
        else -> "nomor tidak dikenal"
    }
    println("Hari ke-$hari: $namaHari")

    // when atas range
    val nilai = 84
    val predikat = when (nilai) {
        in 85..100 -> "A"
        in 70..84 -> "B"
        in 60..69 -> "C"
        else -> "D"
    }
    println("Nilai $nilai memperoleh predikat $predikat")

    // when atas tipe dengan Any
    val data: Any = 24
    val deskripsi = when (data) {
        is String -> "teks dengan panjang ${data.length}"
        is Int -> "bilangan bulat"
        is Double -> "bilangan desimal"
        else -> "tipe lain"
    }
    println("Data $data adalah $deskripsi")

    // when tanpa subjek
    val suhu = 31
    val keterangan = when {
        suhu >= 30 -> "panas"
        suhu >= 20 -> "normal"
        else -> "dingin"
    }
    println("Suhu $suhu derajat termasuk $keterangan")
}

Kompilasi dan jalankan dengan perintah berikut. Jalur instalasi kotlinc mengikuti lingkungan kerja modul ini dan perlu disesuaikan dengan lokasi instalasi pada komputer lain.

bash
# siapkan alat kompilasi Kotlin pada lingkungan kerja ini
export PATH=/home/kal/my-project/tools/kotlinc/bin:/home/kal/my-project/tools/jdk-merged/bin:$PATH
export STDLIB=/home/kal/my-project/tools/kotlinc/lib/kotlin-stdlib.jar

# kompilasi main.kt menjadi out.jar, lalu jalankan kelas MainKt
kotlinc main.kt -d out.jar && java -cp "out.jar:$STDLIB" MainKt
text Keluaran
Hari ke-3: Rabu
Nilai 84 memperoleh predikat B
Data 24 adalah bilangan bulat
Suhu 31 derajat termasuk panas

Empat baris keluaran masing-masing berasal dari satu bentuk when. Angka 3 jatuh pada cabang 3 -> "Rabu", sedangkan nilai 84 masuk ke rentang in 70..84. Nilai data bertipe Int sehingga cabang is Int terpilih, dan suhu 31 memenuhi kondisi pertama pada when tanpa subjek. Semua hasil mengikuti aturan yang sama, yaitu cabang pertama yang cocok menang.

Kesalahan umum#

Kesalahan pertama adalah memakai when sebagai ekspresi tanpa menutup semua kemungkinan. Penulisan val label = when (hari) { 1 -> "Senin" } ditolak compiler karena nilai hari lain tidak memiliki cabang. Perbaikannya adalah menambahkan else, atau memperluas pola hingga semua nilai tercakup.

Kesalahan kedua adalah mengira cabang else selalu wajib. Pada bentuk pernyataan, when tanpa else sah selama hasilnya tidak dipakai sebagai nilai. Penolakan compiler baru muncul ketika hasilnya disimpan atau dikembalikan.

Kesalahan ketiga adalah lupa kata in saat mencocokkan rentang. Cabang 85..100 -> ... tanpa in membandingkan subjek dengan objek range secara keseluruhan, bukan memeriksa keanggotaannya, sehingga cabang itu tidak pernah cocok untuk nilai tunggal. Tulis in 85..100 agar pemeriksaan keanggotaan yang dijalankan. Kebiasaan yang murah untuk menghindari ketiganya adalah menguji when dengan beberapa nilai, baik yang berada di dalam maupun di luar rentang, sebelum kode dipakai lebih luas.

Ringkasan#

  • when mencocokkan subjek terhadap pola nilai, beberapa nilai yang dipisah koma, range dengan in, dan tipe dengan is.
  • Cabang pertama yang cocok menang, dan cabang setelahnya tidak dieksekusi.
  • when tanpa subjek menggantikan rantai else if dengan kondisi Boolean pada setiap cabang.
  • when sebagai ekspresi wajib lengkap, dan else menjadi penutup yang paling umum.

Referensi#