Setiap developer Kotlin bertemu galat yang sama berulang kali: Unresolved reference, NullPointerException dari Java interop, ConcurrentModificationException, hingga OutOfMemoryError. Mengenali pola pesan galat mempercepat debugging. Pada chapter ini kita kumpulkan galat paling umum beserta penyebab dan solusinya, lalu mendemokan teknik penanganan nullable yang aman: safe call ?., elvis ?:, safe cast as?, getOrNull, serta require dan check.

Galat Kompilator Umum #

Pesan galatPenyebabSolusi
Unresolved reference: XSymbol tidak ditemukan — typo atau import hilangTambah import, periksa ejaan, rebuild project
Type mismatch: inferred type X but Y was expectedTipe tidak cocok — biasanya null vs non-nullTambah ? untuk nullable, atau gunakan !! untuk non-null assertion
Null can not be a value of a non-null type StringMemberi null ke variabel non-nullableUbah tipe ke String? atau beri nilai default
Only safe (?.) or non-null asserted (!!.) calls are allowedMemanggil method pada nullable tanpa cek nullPakai ?. (safe call), ?: (elvis), atau !! (forced)
Overload resolution ambiguityKompilator tidak tahu method mana yang dipanggilTentukan tipe eksplisit: foo(x as String)

Runtime Exception Umum #

Runtime exception terjadi saat program berjalan, bukan saat kompilasi. Lima exception paling sering: NullPointerException (biasanya dari Java interop), ClassCastException (cast ke tipe salah), IndexOutOfBoundsException (akses list di luar batas), ConcurrentModificationException (modifikasi list saat iterasi), dan OutOfMemoryError (heap JVM tidak cukup).

Cuplikan berikut mendemokan empat teknik penanganan yang aman: safe call ?., elvis ?:, safe cast as?, getOrNull, serta require dan check:

kotlin
// troubleshooting.kt
// Daftar kesalahan umum dan cara memperbaikinya.
// Disusun per kategori: compiler error, runtime exception, build problem.

import java.io.IOException

fun main() {
    println("=== Troubleshooting Kotlin ===")
    println("Kesalahan umum dan cara memperbaikinya.")
    println()

    println("--- 1. Compiler error umum ---")
    val compilerErrors = listOf(
        Triple(
            "Unresolved reference: X",
            "Symbol tidak ditemukan — typo, atau import hilang",
            "Tambah import, periksa ejaan, rebuild project"
        ),
        Triple(
            "Type mismatch: inferred type X but Y was expected",
            "Tipe tidak cocok — biasanya null vs non-null",
            "Tambah ? untuk nullable, atau gunakan !! untuk non-null assertion"
        ),
        Triple(
            "Null can not be a value of a non-null type String",
            "Memberi null ke variabel non-nullable",
            "Ubah tipe ke String? atau beri nilai default"
        ),
        Triple(
            "Only safe (?.) or non-null asserted (!!.) calls are allowed",
            "Memanggil method pada nullable tanpa cek null",
            "Pakai ?. (safe call), ?: (elvis), atau !! (forced)"
        ),
        Triple(
            "Overload resolution ambiguity",
            "Kompilator tidak tahu method mana yang dipanggil",
            "Tentukan tipe eksplisit: foo(x as String)"
        )
    )
    compilerErrors.forEach { (err, cause, fix) ->
        println("  $err")
        println("    Penyebab : $cause")
        println("    Solusi   : $fix")
    }

    println()
    println("--- 2. Runtime exception umum ---")
    val runtimeErrors = listOf(
        Triple(
            "NullPointerException",
            "Mengakses member dari null (terutama dari Java interop)",
            "Aktifkan strict null-safety; gunakan ?. atau ?:"
        ),
        Triple(
            "ClassCastException",
            "Cast ke tipe yang salah",
            "Pakai smart cast via `is`, atau `as?` untuk safe cast"
        ),
        Triple(
            "IndexOutOfBoundsException",
            "Akses list[index] di luar batas",
            "Pakai getOrNull(index) atau cek size dulu"
        ),
        Triple(
            "ConcurrentModificationException",
            "Modifikasi list saat iterasi",
            "Pakai iterator.remove() atau filter/map untuk hasil baru"
        ),
        Triple(
            "IllegalArgumentException",
            "Argumen tidak valid (mis. require(x > 0))",
            "Validasi input sebelum panggil; tangkap bila perlu"
        ),
        Triple(
            "OutOfMemoryError: Java heap space",
            "Heap JVM tidak cukup",
            "Tambah -Xmx; periksa memory leak"
        )
    )
    runtimeErrors.forEach { (err, cause, fix) ->
        println("  $err")
        println("    Penyebab : $cause")
        println("    Solusi   : $fix")
    }

    println()
    println("--- 3. Build problem umum ---")
    val buildProblems = listOf(
        Triple(
            "Could not resolve dependency",
            "Repository tidak punya versi tersebut",
            "Periksa versi, tambah mavenCentral()/google() di settings"
        ),
        Triple(
            "Kotlin compiler version mismatch",
            "Plugin Kotlin dan stdlib versi berbeda",
            "Pakai plugin kotlin BOM, atau pin versi eksplisit"
        ),
        Triple(
            "JVM target 1.8 vs 21 mismatch",
            "java sourceCompatibility != kotlin jvmTarget",
            "Set kotlin { jvmToolchain(21) } agar konsisten"
        ),
        Triple(
            "Unresolved reference: kotlinx",
            "Library coroutine/serialization belum ditambah",
            "Tambah implementation(\"org.jetbrains.kotlinx:kotlinx-coroutines-core:...\")"
        )
    )
    buildProblems.forEach { (err, cause, fix) ->
        println("  $err")
        println("    Penyebab : $cause")
        println("    Solusi   : $fix")
    }

    println()
    println("--- 4. Demo: amankan nullable dengan safe call ---")
    val nama: String? = null
    println("  nama = $nama")
    println("  nama?.length = ${nama?.length}")          // null
    println("  nama?.length ?: 0 = ${nama?.length ?: 0}") // 0
    println("  nama ?: \"default\" = ${nama ?: "default"}")

    println()
    println("--- 5. Demo: safe cast (as?) ---")
    val x: Any = "halo"
    val asInt: Int? = x as? Int   // null, tidak throw ClassCastException
    println("  x = $x  (${x::class.simpleName})")
    println("  x as? Int = $asInt  (null bila gagal cast)")

    println()
    println("--- 6. Demo: getOrNull untuk akses aman ---")
    val daftar = listOf(10, 20, 30)
    println("  daftar = $daftar")
    println("  daftar.getOrNull(1) = ${daftar.getOrNull(1)}")  // 20
    println("  daftar.getOrNull(5) = ${daftar.getOrNull(5)}")  // null

    println()
    println("--- 7. Demo: cek kondisi (require / check) ---")
    fun setUmur(umur: Int) {
        require(umur >= 0) { "Umur tidak boleh negatif, dapat $umur" }
        check(umur < 200) { "Umur tidak realistis: $umur" }
        println("  Umur diset: $umur")
    }
    setUmur(25)
    try {
        setUmur(-1)
    } catch (e: IllegalArgumentException) {
        println("  IllegalArgumentException: ${e.message}")
    }

    println()
    println("--- 8. Demo: tangani IOException ---")
    fun bacaFile(nama: String): String {
        return try {
            // Simulasi baca file (selalu sukses di sini)
            if (nama == "missing.txt") throw IOException("file tidak ditemukan")
            "isi file $nama"
        } catch (e: IOException) {
            "(error: ${e.message})"
        }
    }
    println("  bacaFile(\"data.txt\")    = ${bacaFile("data.txt")}")
    println("  bacaFile(\"missing.txt\") = ${bacaFile("missing.txt")}")

    println()
    println("--- 9. Aturan debugging umum ---")
    val aturan = listOf(
        "1. Baca pesan kesalahan lengkap — jangan tebak",
        "2. Reproduksi di lokal (minimal test case)",
        "3. Print/log nilai variabel di lokasi gagal",
        "4. Pakai debugger IntelliJ (breakpoint, step over)",
        "5. Sederhanakan kode sampai bug hilang; bandingkan versi",
        "6. Baca stacktrace dari atas ke bawah",
        "7. Cari di Stack Overflow / issue tracker Kotlin",
        "8. Bila masih buntu, buat minimal repro dan ajukan ke forum"
    )
    aturan.forEach { println("  $it") }
}

Output yang Dihasilkan:

text
=== Troubleshooting Kotlin ===
Kesalahan umum dan cara memperbaikinya.

--- 1. Compiler error umum ---
  Unresolved reference: X
    Penyebab : Symbol tidak ditemukan — typo, atau import hilang
    Solusi   : Tambah import, periksa ejaan, rebuild project
  Type mismatch: inferred type X but Y was expected
    Penyebab : Tipe tidak cocok — biasanya null vs non-null
    Solusi   : Tambah ? untuk nullable, atau gunakan !! untuk non-null assertion
  Null can not be a value of a non-null type String
    Penyebab : Memberi null ke variabel non-nullable
    Solusi   : Ubah tipe ke String? atau beri nilai default
  Only safe (?.) or non-null asserted (!!.) calls are allowed
    Penyebab : Memanggil method pada nullable tanpa cek null
    Solusi   : Pakai ?. (safe call), ?: (elvis), atau !! (forced)
  Overload resolution ambiguity
    Penyebab : Kompilator tidak tahu method mana yang dipanggil
    Solusi   : Tentukan tipe eksplisit: foo(x as String)

--- 2. Runtime exception umum ---
  NullPointerException
    Penyebab : Mengakses member dari null (terutama dari Java interop)
    Solusi   : Aktifkan strict null-safety; gunakan ?. atau ?:
  ClassCastException
    Penyebab : Cast ke tipe yang salah
    Solusi   : Pakai smart cast via `is`, atau `as?` untuk safe cast
  IndexOutOfBoundsException
    Penyebab : Akses list[index] di luar batas
    Solusi   : Pakai getOrNull(index) atau cek size dulu
  ConcurrentModificationException
    Penyebab : Modifikasi list saat iterasi
    Solusi   : Pakai iterator.remove() atau filter/map untuk hasil baru
  IllegalArgumentException
    Penyebab : Argumen tidak valid (mis. require(x > 0))
    Solusi   : Validasi input sebelum panggil; tangkap bila perlu
  OutOfMemoryError: Java heap space
    Penyebab : Heap JVM tidak cukup
    Solusi   : Tambah -Xmx; periksa memory leak

--- 3. Build problem umum ---
  Could not resolve dependency
    Penyebab : Repository tidak punya versi tersebut
    Solusi   : Periksa versi, tambah mavenCentral()/google() di settings
  Kotlin compiler version mismatch
    Penyebab : Plugin Kotlin dan stdlib versi berbeda
    Solusi   : Pakai plugin kotlin BOM, atau pin versi eksplisit
  JVM target 1.8 vs 21 mismatch
    Penyebab : java sourceCompatibility != kotlin jvmTarget
    Solusi   : Set kotlin { jvmToolchain(21) } agar konsisten
  Unresolved reference: kotlinx
    Penyebab : Library coroutine/serialization belum ditambah
    Solusi   : Tambah implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:...")

--- 4. Demo: amankan nullable dengan safe call ---
  nama = null
  nama?.length = null
  nama?.length ?: 0 = 0
  nama ?: "default" = default

--- 5. Demo: safe cast (as?) ---
  x = halo  (String)
  x as? Int = null  (null bila gagal cast)

--- 6. Demo: getOrNull untuk akses aman ---
  daftar = [10, 20, 30]
  daftar.getOrNull(1) = 20
  daftar.getOrNull(5) = null

--- 7. Demo: cek kondisi (require / check) ---
  Umur diset: 25
  IllegalArgumentException: Umur tidak boleh negatif, dapat -1

--- 8. Demo: tangani IOException ---
  bacaFile("data.txt")    = isi file data.txt
  bacaFile("missing.txt") = (error: file tidak ditemukan)

--- 9. Aturan debugging umum ---
  1. Baca pesan kesalahan lengkap — jangan tebak
  2. Reproduksi di lokal (minimal test case)
  3. Print/log nilai variabel di lokasi gagal
  4. Pakai debugger IntelliJ (breakpoint, step over)
  5. Sederhanakan kode sampai bug hilang; bandingkan versi
  6. Baca stacktrace dari atas ke bawah
  7. Cari di Stack Overflow / issue tracker Kotlin
  8. Bila masih buntu, buat minimal repro dan ajukan ke forum

Perhatikan lima demo yang dicetak: safe call ?. dan elvis ?: pada null, safe cast as? yang mengembalikan null alih-alih throw, getOrNull yang mengembalikan null untuk indeks di luar batas, require yang melempar IllegalArgumentException untuk input negatif, serta try-catch pada IOException simulasi.

Aturan Debugging Umum #

Saat menemui galat, ikuti urutan berikut: baca pesan kesalahan lengkap (jangan tebak), reproduksi di lokal dengan minimal test case, cetak atau log nilai variabel di lokasi gagal, gunakan debugger IntelliJ dengan breakpoint, sederhanakan kode sampai bug hilang lalu bandingkan versi, baca stacktrace dari atas ke bawah, cari di Stack Overflow atau issue tracker Kotlin. Bila masih buntu, buat minimal repro dan ajukan ke forum Kotlin Slack atau GitHub Discussions.

Referensi Lanjutan #

Selanjutnya #

Debugging lebih cepat bila kita paham kosakata teknisnya. Chapter berikutnya adalah glosarium — kumpulan istilah Kotlin dengan definisi singkat dan contoh kode.