Setiap programmer Kotlin pasti berpapasan dengan pesan kesalahan — baik dari kompilator maupun dari runtime. Pada chapter ini kita akan membedah anatomi pesan error kotlinc, mengurai format file:line:col hingga penanda caret, lalu belajar membaca stack trace saat runtime. Dengan memahami pola pesan kesalahan, kita dapat mempercepat siklus edit-kompilasi-jalankan dan menemukan akar masalah tanpa menebak-nebak.

Anatomi Pesan Error Kompilator #

Kompilator kotlinc mengeluarkan pesan kesalahan dalam format yang konsisten. Berikut cuplikan kode sengaja dibuat salah dengan type mismatch:

kotlin error.kt — kode sengaja salah untuk demonstrasi
fun main() {
    val umur: Int = "dua puluh lima"
    println("Umur: $umur")
}

Saat dikompilasi, kotlinc mengeluarkan pesan berikut:

text Output kotlinc untuk error.kt
error.kt:2:21: error: initializer type mismatch: expected 'kotlin.Int', actual 'kotlin.String'.
    val umur: Int = "dua puluh lima"
                    ^^^^^^^^^^^^^^^^

Mari kita bedah bagian-bagian pesan di atas:

  1. error.kt:2:21 — lokasi kesalahan: file error.kt, baris ke-2, kolom ke-21. Kolom dihitung mulai dari 1 di awal baris.
  2. error: — tingkat keparahan. Kompilator Kotlin juga memancarkan warning: untuk hal yang tidak fatal.
  3. initializer type mismatch: expected 'kotlin.Int', actual 'kotlin.String'. — deskripsi kesalahan. Pesan ini menyatakan bahwa tipe initializer (String) tidak cocok dengan tipe yang dideklarasikan (Int).
  4. Baris kode yang ditampilkan ulang — kompilator menyalin baris yang bermasalah agar pembaca tidak perlu bergulir ke file.
  5. ^^^^^^^^^^^^^^^^ — caret menunjuk persis token yang menjadi sumber kesalahan. Panjang caret sesuai dengan panjang token "dua puluh lima".

Tiga Sumber Kesalahan Kompilator #

Pesan error kotlinc umumnya jatuh pada tiga kategori:

KategoriContoh pesanPenyebab umum
Type mismatchexpected 'kotlin.Int', actual 'kotlin.String'Variabel diisi nilai dengan tipe berbeda
Unresolved referenceunresolved reference: namaVariabelSalah ketik nama; lupa import
Type inference failuretype mismatch: inferred type is X but Y was expectedLambda atau return type tidak konsisten
Modifier conflict'final' member cannot be overriddenMencoba override method final

Setiap kategori punya pola perbaikan berbeda. Type mismatch diselesaikan dengan mengubah tipe atau nilai; unresolved reference diselesaikan dengan import atau memperbaiki ejaan.

Membaca file:line:col #

Lokasi file:line:col adalah informasi paling penting saat menelusuri kesalahan. Mari kita pecah satu contoh:

text Format lokasi kotlinc
path/ke/file.kt:13:7
^^^^^^^^^^^^^^^^ ^^^ ^^
        |          |   |
   nama file       |   |
                baris  |
                     kolom
  • Baris dimulai dari 1.
  • Kolom dimulai dari 1, dihitung sebagai posisi karakter dari awal baris (termasuk spasi dan tab).
  • Beberapa editor seperti IntelliJ IDEA dapat melompat langsung ke lokasi ini saat kita mengklik pesan error.

Caret Menunjuk Sumber Masalah #

Caret (^^^^^^) di bawah baris kode menandai persis token yang menjadi sumber kesalahan. Perhatikan contoh berikut:

text Caret menunjuk token yang salah
error.kt:2:21: error: initializer type mismatch: expected 'kotlin.Int', actual 'kotlin.String'.
    val umur: Int = "dua puluh lima"
                    ^^^^^^^^^^^^^^^^

Caret hanya menutupi literal string "dua puluh lima", bukan seluruh baris. Ini memberi tahu kita bahwa masalahnya ada pada literal string, bukan pada deklarasi val umur: Int. Solusinya jelas: ganti literal string dengan literal integer seperti 25, atau ubah tipe variabel menjadi String.

Stack Trace saat Runtime #

Kesalahan yang lolos dari kompilasi muncul saat runtime sebagai exception. Berikut program sengaja memicu IndexOutOfBoundsException dan menangkap jejak tumpukan (stack trace):

kotlin
fun main() {
    val daftar = listOf("Budi", "Siti", "Andi")
    println("Daftar peserta: $daftar")
    try {
        val indeks = 5
        val nama = daftar[indeks]
        println("Peserta ke-$indeks: $nama")
    } catch (e: IndexOutOfBoundsException) {
        println("Terjadi kesalahan: ${e::class.simpleName}")
        println("Pesan: ${e.message}")
        println("Jejak tumpukan (3 baris pertama):")
        e.stackTrace.take(3).forEach { elem ->
            println("  at $elem")
        }
    }
}

Output yang Dihasilkan:

text
Daftar peserta: [Budi, Siti, Andi]
Terjadi kesalahan: ArrayIndexOutOfBoundsException
Pesan: Index 5 out of bounds for length 3
Jejak tumpukan (3 baris pertama):
  at java.base/java.util.Arrays$ArrayList.get(Arrays.java:4266)
  at StacktraceKt.main(stacktrace.kt:6)
  at StacktraceKt.main(stacktrace.kt)

Mari kita bedah output stack trace:

  1. ArrayIndexOutOfBoundsException — nama class exception. Nama ini menyatakan jenis masalah: kita mengakses indeks di luar batas array/list.
  2. Index 5 out of bounds for length 3 — pesan exception. Pesan ini menyatakan bahwa indeks 5 di luar batas untuk daftar dengan panjang 3.
  3. at java.base/java.util.Arrays$ArrayList.get(Arrays.java:4266) — baris pertama stack trace, menunjukkan method internal JDK tempat exception dilempar. Baris ini biasanya bukan akar masalah kita.
  4. at StacktraceKt.main(stacktrace.kt:6) — baris kedua menunjukkan kode kita sendiri. File stacktrace.kt baris 6 adalah tempat pemanggilan daftar[indeks].
  5. at StacktraceKt.main(stacktrace.kt) — baris ketiga adalah wrapper entry point sintetik yang dibuat kompilator Kotlin.

Strategi Membaca Stack Trace #

Saat membaca stack trace, ikuti urutan berikut:

  1. Baca nama exception dan pesannya — sering kali sudah cukup untuk menebak akar masalah (NullPointerException, IllegalArgumentException, IndexOutOfBoundsException).
  2. Cari baris yang merujuk ke kode kita sendiri — lewati baris dari java.base, kotlin.collections, atau library pihak ketiga. Baris dengan nama file kode kita adalah kandidat utama.
  3. Baca baris terdekat dengan akar masalah — stack trace biasanya menampilkan frame paling dalam (tempat exception dilempar) di atas, dan frame pemanggil di bawah. Mulai dari atas, cari frame pertama yang merujuk ke kode kita.
  4. Telusuri kode di baris tersebut — buka file pada baris yang ditunjuk, periksa nilai variabel lokal dan asumsi yang mungkin salah.

Pesan Error yang Sering Muncul #

Tabel berikut merangkum pesan error yang sering muncul beserta penanganan umum:

PesanPenyebabPenanganan
unresolved reference: xSalah ketik atau lupa importPeriksa ejaan; tambahkan import
type mismatch: inferred type is X but Y was expectedLambda atau return type tidak konsistenSesuaikan tipe parameter atau return
variable 'x' must be initializedVariabel val dipakai sebelum diisiPindahkan inisialisasi sebelum pemakaian
null cannot be a value of a non-null type StringMemberi null pada tipe non-nullableUbah tipe menjadi String? atau beri nilai non-null
only safe (?.) or non-null asserted (!!.) calls are allowedMemanggil method pada nullable tanpa cek nullPakai ?. atau !! dengan hati-hati
ArrayIndexOutOfBoundsExceptionAkses indeks di luar batasPeriksa panjang sebelum akses
NumberFormatExceptionParsing string non-numerikValidasi input sebelum toInt()

Referensi Lanjutan #

Membaca pesan error dengan teliti adalah keterampilan yang berkembang seiring latihan. Setelah memahami anatomi pesan kompilator dan stack trace runtime, kita siap masuk ke materi variabel dan tipe data Kotlin — pembahasan lengkap menanti pada section Variabel dan Tipe Data.