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 galat | Penyebab | Solusi |
|---|---|---|
Unresolved reference: X | Symbol tidak ditemukan — typo atau import hilang | Tambah import, periksa ejaan, rebuild project |
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 |
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 |
Only safe (?.) or non-null asserted (!!.) calls are allowed | Memanggil method pada nullable tanpa cek null | Pakai ?. (safe call), ?: (elvis), atau !! (forced) |
Overload resolution ambiguity | Kompilator tidak tahu method mana yang dipanggil | Tentukan 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:
// 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:
=== 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 forumPerhatikan 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 #
- Kotlin documentation home — halaman utama dokumentasi Kotlin untuk menelusuri pesan galat compiler dan catatan rilis
Selanjutnya #
Debugging lebih cepat bila kita paham kosakata teknisnya. Chapter berikutnya adalah glosarium — kumpulan istilah Kotlin dengan definisi singkat dan contoh kode.