Saat program Kotlin melempar exception yang tidak tertangkap, JVM mencetak stack trace ke konsol. Stack trace adalah jejak pemanggilan method pada momen exception dilempar. Membaca stack trace dengan cepat dan tepat adalah keterampilan dasar yang menentukan seberapa cepat kita dapat menemukan akar masalah. Pada chapter ini kita akan membongkar anatomi stack trace, memahami urutan innermost ke outermost, serta cara membaca pola Caused by untuk exception berantai.
Anatomi Stack Trace #
Stack trace standar JVM terdiri atas beberapa bagian:
Exception in thread "main" java.lang.IllegalArgumentException: Pelanggan tidak boleh null
at Stack_trace_demoKt.validasiPelanggan(stack_trace_demo.kt:23)
at Stack_trace_demoKt.prosesPesanan(stack_trace_demo.kt:17)
at Stack_trace_demoKt.main(stack_trace_demo.kt:4)
at Stack_trace_demoKt.main(stack_trace_demo.kt:-1)Mari kita bedah elemen-elemen di atas:
Exception in thread "main": thread tempat exception dilempar. Untuk aplikasi multi-thread, ini mengidentifikasi thread mana yang bermasalah.java.lang.IllegalArgumentException: ...: tipe exception dan pesan. Pesan biasanya berisi konteks spesifik (mis. “Pelanggan tidak boleh null”).at ... .validasiPelanggan(stack_trace_demo.kt:23): satu frame stack. Formatnya adalahClass.method(file:line).- Urutan frame: frame pertama adalah innermost (method yang sedang dieksekusi saat exception dilempar). Frame terakhir adalah outermost (method paling luar, biasanya
main).
Urutan Innermost ke Outermost #
Banyak developer baru membaca stack trace dari atas ke bawah dan langsung melompat ke baris pertama. Ini benar, tetapi perlu diinghat bahwa baris pertama adalah tempat exception dilempar, bukan akar penyebab. Untuk memahami alur, kita perlu membaca dari atas (innermost) ke bawah (outermost) dan menelusuri rantai pemanggilan secara terbalik.
Sebaliknya, bila kita ingin tahu siapa yang memanggil method ini, kita membaca frame kedua dan seterusnya. Pola umum: frame pertama menunjukkan di mana masalah terjadi, frame kedua menunjukkan siapa yang memanggil kode bermasalah.
Demonstrasi Stack Trace #
Kode berikut menghasilkan exception dengan tiga level pemanggilan method, lalu menangkap dan mencetak stack trace secara terkontrol.
fun main() {
println("=== Demonstrasi Stack Trace ===")
try {
prosesPesanan(null)
} catch (e: Exception) {
println("Tertangkap di main: ${e::class.simpleName}")
println("Pesan: ${e.message}")
println()
println("Stack trace (5 frame teratas):")
e.stackTrace.take(5).forEachIndexed { i, frame ->
println(" [$i] ${frame.className}.${frame.methodName}(${frame.fileName}:${frame.lineNumber})")
}
}
}
fun prosesPesanan(pelanggan: String?) {
validasiPelanggan(pelanggan)
println("Memproses pesanan untuk $pelanggan")
}
fun validasiPelanggan(pelanggan: String?) {
if (pelanggan == null) {
throw IllegalArgumentException("Pelanggan tidak boleh null")
}
println("Pelanggan valid: $pelanggan")
}Output yang Dihasilkan:
=== Demonstrasi Stack Trace ===
Tertangkap di main: IllegalArgumentException
Pesan: Pelanggan tidak boleh null
Stack trace (5 frame teratas):
[0] Stack_trace_demoKt.validasiPelanggan(stack_trace_demo.kt:23)
[1] Stack_trace_demoKt.prosesPesanan(stack_trace_demo.kt:17)
[2] Stack_trace_demoKt.main(stack_trace_demo.kt:4)
[3] Stack_trace_demoKt.main(stack_trace_demo.kt:-1)Mari kita telaah kode dan output di atas:
- Rantai pemanggilan:
mainmemanggilprosesPesanan(null), yang memanggilvalidasiPelanggan(null). Stack trace mencerminkan urutan ini — frame[0]adalahvalidasiPelanggan(innermost),[1]adalahprosesPesanan,[2]adalahmain. e.stackTrace.take(5): arrayStackTraceElementdiakses secara terprogram. Kita memakaitake(5)untuk membatasi 5 frame teratas — berguna saat log ke file untuk mengurangi noise.forEachIndexed: iterasi dengan index untuk menampilkan nomor frame. Frame paling atas ([0]) adalah method yang melempar exception.fileName:lineNumber: informasi paling penting untuk debugging. Bila kode dikompilasi dengan-g(debug info), nomor baris akurat. Tanpa-g, beberapa frame mungkin menampilkan:-1.
Pola “Caused by” #
Saat exception dibungkus (mis. throw RuntimeException("gagal", cause)), stack trace memiliki bagian Caused by:
java.lang.RuntimeException: Gagal memproses pesanan
at App.prosesPesanan(App.kt:10)
at App.main(App.kt:4)
Caused by: java.lang.IllegalArgumentException: Pelanggan null
at App.validasi(App.kt:20)
at App.prosesPesanan(App.kt:8)
... 1 moreBagian Caused by menampilkan exception asli yang dibungkus. Untuk menemukan akar masalah, baca dari Caused by ke atas — ini biasanya adalah exception paling awal yang memicu rantai. Bila ada beberapa level wrapping, akan ada beberapa Caused by bertingkat.
Tips Membaca Stack Trace #
Beberapa aturan praktis untuk membaca stack trace dengan cepat:
- Baca pesan exception terlebih dahulu — biasanya berisi tipe dan deskripsi singkat.
- Cari baris pertama yang berasal dari kode kita sendiri — frame dari library eksternal (
java.base,kotlin.stdlib) biasanya bukan akar masalah, melainkan konsekuensi dari masalah di kode kita. - Telusuri rantai
Caused bysampai ke exception paling awal — ini biasanya adalah akar penyebab. - Periksa nomor baris di file sumber kita — buka file, lompat ke baris tersebut, dan baca kode sekitarnya.
- Bila ada beberapa thread, pastikan membaca stack trace thread yang benar (lihat label
Exception in thread "...").
Referensi Lanjutan #
- IntelliJ IDEA Debugging — panduan resmi IntelliJ IDEA untuk membaca stack trace dan debugging kode
Penutup #
Kemampuan membaca stack trace adalah keterampilan yang berkembang dengan latihan. Setiap stack trace yang kita analisis membangun intuisi tentang pola error umum (null pointer, index out of bounds, class cast) dan lokasi tipikalnya. Pada chapter berikutnya kita akan naik ke alat yang lebih interaktif: IDE debugger untuk menjeda eksekusi dan memeriksa state program saat runtime.