Menangkap Exception Alih-alih Crash
Kamu sudah tahu bahwa saat terjadi masalah, Java melempar exception, dan exception yang tidak ditangani akan menghentikan programmu dengan stack trace. Blok try-catch adalah cara kamu mengambil kendali: kamu membungkus kode yang berisiko di dalam try, dan kalau kode itu melempar exception, Java melompat ke blok catch yang cocok alih-alih crash.
Begitu 10 / 0 melempar exception, sisa blok try dilewati dan alur program pindah ke catch. Setelah catch selesai, eksekusi berlanjut seperti biasa, jadi program tidak mati.
Variabel catch Berisi Exception-nya
e di catch (ArithmeticException e) adalah objek sungguhan. Objek ini membawa informasi tentang apa yang salah, dan yang paling berguna adalah pesannya:
e.getMessage() mengembalikan deskripsi singkat. Saat debugging, e.printStackTrace() menampilkan trace lengkap yang menunjukkan dengan tepat dari mana exception itu berasal. Pakai itu kalau pesan saja tidak cukup untuk menemukan penyebabnya.
Tangkap Tipe yang Spesifik, Bukan Semuanya
Blok catch hanya menangkap exception yang cocok dengan tipe yang dideklarasikannya (atau subclass-nya). Kesalahan pemula yang paling besar adalah menangkap Exception supaya masalahnya "hilang":
// Don't do this - it hides real bugs
try {
doWork();
} catch (Exception e) {
// swallows NullPointerException, typos, logic errors... everything
}
Tangkap tipe paling sempit yang benar-benar bisa kamu tangani. Kalau kamu mengantisipasi input angka yang salah, tangkap NumberFormatException. Apa pun yang tidak kamu antisipasi sebaiknya dibiarkan menjalar keluar, supaya kamu benar-benar mengetahuinya, bukan diam-diam melanjutkan program dalam keadaan rusak.
Menangani Beberapa Tipe Exception
Kamu bisa menumpuk beberapa blok catch. Java memeriksanya dari atas ke bawah dan menjalankan yang pertama cocok, jadi urutkan dari yang paling spesifik ke yang paling umum:
Kalau dua tipe ditangani dengan cara yang sama, pakai satu multi-catch dengan | alih-alih menduplikasi bloknya:
Satu jebakan: tipe yang lebih umum harus ditulis setelah tipe yang spesifik. Menaruh catch (Exception e) di urutan pertama membuat blok-blok yang lebih spesifik di bawahnya tidak pernah bisa dicapai, dan compiler akan menolaknya.
finally Selalu Berjalan
Blok finally berjalan setelah try dan catch mana pun, apa pun yang terjadi: berhasil, exception yang tertangkap, atau bahkan return lebih awal. Di sinilah tempat pembersihan yang harus selalu terjadi.
"Closing resource" tetap dicetak, entah exception-nya terjadi atau tidak. Tapi hindari melakukan return dari dalam finally, karena bisa diam-diam membuang exception atau menimpa nilai yang dikembalikan dari blok try.
try-with-resources Menutupnya untukmu
Saat kamu bekerja dengan sesuatu yang harus ditutup, seperti file, koneksi jaringan, atau statement database, mendeklarasikannya di dalam try (...) akan menutupnya secara otomatis saat blok selesai, bahkan kalau exception dilempar. Tipe apa pun yang mengimplementasikan interface AutoCloseable bisa dipakai.
Cara ini menggantikan pola lama yang membuka di try lalu menutup di finally, dan lebih kecil kemungkinan salahnya karena kamu tidak mungkin lupa menutupnya. Utamakan cara ini setiap kali kamu berurusan dengan resource yang bisa ditutup.
Jangan Pakai Exception untuk Alur Program Biasa
try-catch dibuat untuk situasi yang luar biasa, bukan kondisi biasa. Menangkap exception lebih mahal daripada pengecekan biasa, dan membuat kode lebih sulit dibaca. Kalau kamu bisa menguji kondisinya lebih dulu dengan pengecekan if-else, lakukan itu:
// Avoid: using a catch to test for a missing key
try {
process(map.get(key).trim());
} catch (NullPointerException e) {
// handle missing key
}
// Prefer: check explicitly
String value = map.get(key);
if (value != null) {
process(value.trim());
}
Simpan catch untuk hal-hal yang benar-benar di luar kendalimu: input pengguna yang salah, file yang hilang, kegagalan jaringan.
Berikutnya: NullPointerException
Exception paling umum yang akan kamu tangkap (dan kamu sebabkan) di Java adalah NullPointerException. Exception ini muncul begitu kamu memanggil method pada sesuatu yang ternyata null. Berikutnya kita akan membahas dengan tepat apa yang memicunya, cara membaca stack trace-nya, dan kebiasaan yang mencegahnya terjadi sejak awal.
Pertanyaan yang sering diajukan
Bagaimana cara memakai try-catch di Java?
Taruh kode yang mungkin melempar exception di dalam blok try, lalu tambahkan blok catch yang menyebutkan tipe exception yang ingin kamu tangani: try { risky(); } catch (IOException e) { ... }. Kalau kode di try melempar exception yang cocok, Java langsung melompat ke blok catch alih-alih crash. Variabel (e) berisi objek exception-nya, jadi kamu bisa membaca pesannya dengan e.getMessage().
Apa kegunaan blok finally di Java?
Blok finally berjalan setelah try/catch apa pun yang terjadi, entah kodenya berhasil, melempar exception, atau bahkan keluar lebih awal dengan return. Di sinilah tempat pembersihan yang harus selalu terjadi, seperti menutup file atau melepas lock. Untuk menutup resource, try-with-resources biasanya lebih rapi karena menutupnya secara otomatis.
Sebaiknya menangkap Exception atau tipe exception yang spesifik?
Tangkap tipe paling spesifik yang benar-benar bisa kamu tangani. Menangkap Exception (atau lebih buruk lagi, Throwable) menelan setiap masalah, termasuk bug seperti NullPointerException, dan menyembunyikan penyebab aslinya. Tangkap NumberFormatException kalau memang itu yang kamu antisipasi, dan biarkan exception yang tidak terduga menjalar keluar supaya kamu mengetahuinya.