Exception membuat program yang sedang berjalan tetap terkendali ketika kejadian tak terduga muncul, misalnya masukan yang bukan angka atau indeks array di luar batas. Topik ini membahas tiga penyusun utama penanganan exception di Java, yaitu blok try, blok catch, dan blok finally, ditambah multi-catch untuk menangani beberapa tipe exception dalam satu blok. Struktur hierarki Throwable, Error, dan Exception juga diurai lebih dahulu, karena blok catch memilih exception yang ditampungnya berdasarkan hubungan pewarisan antarkelas.
Hierarki Throwable, Error, dan Exception#
Semua exception di Java berakar pada kelas java.lang.Throwable, sehingga hanya objek kelas itu atau turunannya yang dapat dilempar dan ditangkap. Dari Throwable bercabang dua keluarga besar. Kelas Error melaporkan masalah serius pada lingkungan runtime, misalnya memori habis (OutOfMemoryError) atau tumpukan pemanggilan penuh (StackOverflowError). Kondisi semacam itu umumnya tidak dapat dipulihkan oleh kode aplikasi, sehingga Error tidak dimaksudkan untuk ditangkap. Kelas Exception menampung kejadian tak terduga yang wajar ditangani program, seperti kegagalan mengubah teks menjadi angka.
Di bawah Exception terdapat RuntimeException, cabang yang berisi exception akibat kesalahan pemrograman seperti NullPointerException dan ArithmeticException. Cabang selain RuntimeException, misalnya IOException, disebut checked exception karena kompilator menuntut penanganannya, sedangkan RuntimeException beserta turunannya disebut unchecked exception. Gambar berikut memetakan hierarki tersebut beserta contoh kelas pada setiap cabang.
Menangkap exception dengan try dan catch#
Blok try mengapit kode yang berpotensi melempar exception, sedangkan blok catch menampung exception tersebut agar program bisa melanjutkan eksekusi alih-alih berhenti. Pemilihan tipe pada catch menentukan kegagalan mana yang ditampung, sedangkan kegagalan lain tetap bergerak naik ke pemanggilnya. Program berikut membaca dua teks menjadi angka, dan teks kedua sengaja tidak sah.
public class DemoTryCatch {
public static void main(String[] args) {
String[] masukan = {"150", "nol koma lima"};
for (String teks : masukan) {
try {
int angka = Integer.parseInt(teks);
System.out.println("\"" + teks + "\" berhasil dibaca: " + angka);
} catch (NumberFormatException e) {
System.out.println("\"" + teks + "\" bukan angka: " + e.getMessage());
}
System.out.println("Perulangan berlanjut");
}
}
}"150" berhasil dibaca: 150
Perulangan berlanjut
"nol koma lima" bukan angka: For input string: "nol koma lima"
Perulangan berlanjutMenjalankannya dari terminal cukup dengan satu perintah berikut.
# berada di folder tempat DemoTryCatch.java disimpan
java DemoTryCatch.java"150" berhasil dibaca: 150
Perulangan berlanjut
"nol koma lima" bukan angka: For input string: "nol koma lima"
Perulangan berlanjutMetode Integer.parseInt melempar NumberFormatException ketika argumennya tidak dapat diubah menjadi int. Untuk teks "150", konversi berhasil sehingga blok catch dilewati sama sekali. Untuk teks kedua, exception terlempar, eksekusi di dalam try langsung berhenti pada baris pemanggilan parseInt, lalu blok catch menampung objek exceptionnya dalam variabel e. Metode getMessage() mengembalikan pesan yang menyertai lemparan. Setelah blok catch selesai, program berlanjut ke pernyataan setelahnya, tampak dari cetakan Perulangan berlanjut yang muncul dua kali.
Menggabungkan catch dengan multi-catch#
Multi-catch menggabungkan beberapa tipe exception dalam satu blok catch dengan tanda pipa, sehingga penanganan yang sama tidak perlu ditulis berulang. Tanpa fitur ini, dua blok catch dengan tubuh yang hampir sama harus ditulis berurutan, dan perbedaannya mudah terlewat saat disunting. Program berikut membagi dua angka yang masuk sebagai teks, dan kegagalannya bisa datang dari dua arah.
public class DemoMultiCatch {
public static void main(String[] args) {
System.out.println(hitung("12", "4"));
System.out.println(hitung("12", "nol"));
System.out.println(hitung("12", "0"));
}
static int hitung(String teksA, String teksB) {
try {
int a = Integer.parseInt(teksA);
int b = Integer.parseInt(teksB);
return a / b;
} catch (NumberFormatException | ArithmeticException e) {
System.out.println("Masukan tidak sah (" + e.getClass().getSimpleName() + ")");
return 0;
}
}
}3
Masukan tidak sah (NumberFormatException)
0
Masukan tidak sah (ArithmeticException)
0Metode hitung memuat dua sumber kegagalan, yaitu parseInt yang melempar NumberFormatException dan pembagian bulat dengan nol yang melempar ArithmeticException. Keduanya dinyatakan dalam satu catch dengan pemisah pipa, dan variabel e bertipe kelas dasar terdekat dari keduanya. Pemanggilan e.getClass().getSimpleName() menunjukkan tipe exception yang benar-benar terlempar pada setiap kasus, sehingga satu blok tetap mampu membedakan sumber kegagalan bila diperlukan.
Urutan blok catch mengikuti aturan pewarisan. Blok untuk kelas yang lebih umum harus ditulis setelah blok kelas turunannya, karena catch dievaluasi berurutan dari atas ke bawah.
// tidak-dijalankan
try {
int angka = Integer.parseInt(teks);
} catch (Exception e) {
System.out.println("Penangan yang terlalu umum");
} catch (NumberFormatException e) {
System.out.println("Tidak pernah tercapai");
}Kompilator menolak potongan di atas karena Exception sudah mencakup NumberFormatException, sehingga blok kedua mustahil tercapai. Biasanya yang ditulis adalah catch paling spesifik lebih dahulu, lalu catch yang lebih umum setelahnya bila memang dibutuhkan.
Menjamin pembersihan dengan finally#
Blok finally menampung kode yang harus dijalankan apa pun yang terjadi di dalam try, baik eksekusi selesai normal, exception tertangkap, maupun exception lolos tanpa tertangkap. Tugasnya bukan menangani exception, melainkan menjamin pembersihan, sehingga finally biasanya berpasangan dengan catch yang sudah ada. Bentuk try-catch-finally adalah susunan penuhnya, dan bentuk try-finally tanpa catch tetap sah.
public class DemoFinally {
public static void main(String[] args) {
System.out.println("-- Kasus normal");
proses("48");
System.out.println("-- Kasus gagal");
proses("empat");
}
static void proses(String teks) {
try {
System.out.println("Angka: " + Integer.parseInt(teks));
} catch (NumberFormatException e) {
System.out.println("Ditangkap di proses: " + e.getMessage());
} finally {
System.out.println("Blok finally dijalankan");
}
}
}-- Kasus normal
Angka: 48
Blok finally dijalankan
-- Kasus gagal
Ditangkap di proses: For input string: "empat"
Blok finally dijalankanCetakan Blok finally dijalankan muncul pada dua kasus, baik ketika parseInt berhasil maupun gagal. Bila exception di dalam try tidak ditangkap oleh catch mana pun, finally tetap dieksekusi sebelum exception bergerak naik ke pemanggil. Sifat inilah yang menjadikan finally tempat menutup koneksi, berkas, atau sumber daya lain yang penutupannya tidak boleh terlewat. Pola try-finally tanpa catch kini jarang ditulis karena try-with-resources memberikan jaminan penutupan yang lebih ringkas.
Kesalahan umum#
- Menangkap
ExceptionatauThrowabledemi menutup semua kemungkinan. Blok yang terlalu umum menampung pula bug yang seharusnya terlihat, sepertiNullPointerException. Tangkap tipe yang paling sesuai dengan kegagalan yang memang diantisipasi. - Menulis
catch (Exception e)sebelum catch turunannya. Blok di bawahnya mustahil tercapai dan kompilasi ditolak. Letakkan catch yang paling spesifik lebih dahulu. - Membiarkan blok catch kosong. Exception lenyap tanpa jejak, sehingga kegagalan baru terlihat jauh setelah penyebabnya. Catat kejadiannya atau lempar kembali secara sadar.
- Menganggap finally menggantikan nilai kembalian.
returndi dalam try tetap menentukan nilai yang diserahkan, sedangkan tugas finally hanya menjalankan pembersihan.
Ringkasan#
- Semua exception berakar pada
Throwable, yang bercabang menjadiErroruntuk masalah lingkungan runtime danExceptionuntuk kejadian yang wajar ditangani program. trymengapit kode yang berpotensi gagal,catchmenampung exception berdasarkan tipenya, dan blok untuk tipe paling spesifik ditulis lebih dahulu.- Multi-catch menggabungkan beberapa tipe dalam satu blok catch dengan tanda pipa.
finallydijalankan apa pun hasil eksekusi try, sehingga cocok untuk pembersihan yang tidak boleh terlewat.
Referensi#
- Catching and Handling Exceptions — Oracle — panduan try, catch, dan multi-catch pada tutorial resmi Java.
- The finally Block — Oracle — perilaku finally beserta contoh penerapannya.
- Throwable (Java SE 21) — Oracle — dokumentasi kelas Throwable sebagai akar hierarki exception.