Exception adalah mekanisme untuk memutus aliran eksekusi normal ketika kejadian luar biasa terjadi, misalnya nilai yang melanggar rentang atau pembagian dengan nol. Topik ini membahas exception bawaan bahasa, pernyataan raise, penanganan dengan kata exception, dan pemulihan yang disengaja pada kasus nyata. Setelah topik ini dibaca, error dapat dihadapi secara terkendali, yaitu ditangkap, dicatat, dan diikuti langkah pemulihan yang jelas.
Exception bawaan dan pernyataan raise#
Ada menyediakan beberapa exception bawaan, dan empat yang paling sering ditemui dirangkum pada tabel berikut.
| Exception | Kondisi yang memicunya |
|---|---|
Constraint_Error | pelanggaran kendala tipe, misalnya nilai di luar rentang atau indeks di luar batas array |
Program_Error | pelanggaran aturan struktur program |
Storage_Error | memori yang diminta tidak tersedia |
Tasking_Error | komunikasi antar task yang gagal |
Exception yang tidak ditangani menyebabkan program berhenti, dan GNAT mencetak baris yang diawali raised, diikuti nama exception beserta berkas dan baris kejadiannya. Pernyataan raise membangkitkan exception secara eksplisit, dan klausa with pada raise membawa pesan yang dapat dibaca oleh penangannya.
Selain exception bawaan, program dapat mendeklarasikan exception sendiri dengan penulisan seperti Kuota_Habis : exception; pada bagian deklaratif. Deklarasinya umumnya diletakkan pada spesifikasi package agar seluruh pemanggil dapat menanganinya dengan nama yang sama. Exception buatan sendiri membuat maksud kegagalan terbaca dari namanya, sehingga cabang when Kuota_Habis => jauh lebih bermakna daripada menangkap Constraint_Error yang maknanya terlalu umum.
Perambatan exception mengikuti rantai pemanggilan. Exception yang dibangkitkan di dalam subprogram dan tidak ditangani di dalam badannya merambat ke pemanggil, kemudian ke pemanggil berikutnya, sampai ada penangan yang cocok atau program berhenti. Dengan demikian, penempatan penangan adalah keputusan rancangan. Penangan diletakkan pada tingkat yang mengetahui cara memulihkan keadaan, sedangkan tingkat yang lebih rendah cukup membiarkan exception merambat.
Penanganan dinyatakan pada sebuah blok, yaitu bagian program yang diapit begin dan end beserta daftar cabang penanganannya.
declare
Nilai : Integer;
begin
Nilai := Integer'Value ("12x0");
Put_Line ("Nilai:" & Integer'Image (Nilai));
exception
when Constraint_Error =>
Put_Line ("Teks tidak dapat dikonversi menjadi bilangan");
end;Cabang when Constraint_Error => disebut handler, yaitu rangkaian pernyataan yang dieksekusi ketika exception dengan nama itu dibangkitkan di dalam blok. Eksekusi tidak pernah kembali ke pernyataan yang gagal, melainkan berpindah ke pernyataan setelah blok. Apabila exception yang muncul tidak cocok dengan cabang mana pun, exception merambat keluar dari blok menuju pemanggilnya, dan pilihan when others => menangkap semua exception yang belum ditangani cabang sebelumnya.
Pemulihan yang disengaja#
Pemulihan yang disengaja berarti keputusan tentang apa yang dilakukan program setelah error ditangkap, bukan pengabaian error tanpa catatan. Program berikut mencoba mengisi Kuantitas dengan nilai 99 yang melanggar rentang 1 sampai 10. Pemeriksaan rentang merupakan pemeriksaan bawaan bahasa yang aktif tanpa flag tambahan, dan pelanggarannya membangkitkan Constraint_Error.
with Ada.Text_IO; use Ada.Text_IO;
procedure Pulih_Dari_Error is
Usulan : Integer := Integer'Value ("99");
Kuantitas : Integer range 1 .. 10 := 4;
begin
Put_Line ("Kuantitas awal:" & Integer'Image (Kuantitas));
-- Blok dengan penanganan lokal: error ditangkap, program berlanjut.
begin
Kuantitas := Usulan; -- 99 di luar rentang 1 .. 10
Put_Line ("Penugasan berhasil");
exception
when Constraint_Error =>
Put_Line ("Penugasan dibatalkan: nilai" & Integer'Image (Usulan)
& " di luar rentang 1 .. 10");
end;
Put_Line ("Program berlanjut, Kuantitas tetap:"
& Integer'Image (Kuantitas));
end Pulih_Dari_Error;# kompilasi program
gnatmake -q -gnata pulih_dari_error.adb
# jalankan program hasil kompilasi
./pulih_dari_errorKuantitas awal: 4
Penugasan dibatalkan: nilai 99 di luar rentang 1 .. 10
Program berlanjut, Kuantitas tetap: 4Baris Penugasan berhasil tidak pernah dicetak, karena eksekusi berpindah ke handler pada saat pelanggaran rentang terdeteksi. Handler mencatat pembatalan tersebut, dan eksekusi berlanjut dari pernyataan setelah blok, sehingga baris terakhir tetap dicetak. Nilai Kuantitas tetap 4 karena penugasannya dibatalkan, dan inilah makna pemulihan yang disengaja, yaitu keadaan program tetap konsisten setelah error ditangani.
Exception yang dibangkitkan sendiri#
Exception juga dapat dibangkitkan secara eksplisit untuk keadaan yang menurut rancangan tidak boleh terjadi. Program berikut mensimulasikan antrean pembeli di sebuah loket dengan persediaan tiga tiket, dan prosedur Jual_Satu_Tiket membangkitkan Constraint_Error dengan pesan apabila tiket telah habis. Handler pada prosedur menangkap exception tersebut, membaca pesannya melalui fungsi Exception_Message dari package Ada.Exceptions, dan siklus penjualan untuk pembeli berikutnya tetap berjalan.
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Exceptions;
procedure Loket_Antrean is
Sisa_Tiket : Natural := 3;
procedure Jual_Satu_Tiket is
begin
if Sisa_Tiket = 0 then
raise Constraint_Error with "tiket telah habis";
end if;
Sisa_Tiket := Sisa_Tiket - 1;
Put_Line ("Tiket terjual, sisa" & Natural'Image (Sisa_Tiket));
exception
when E : Constraint_Error =>
Put_Line ("Penjualan dihentikan: "
& Ada.Exceptions.Exception_Message (E));
end Jual_Satu_Tiket;
begin
for K in 1 .. 4 loop
Put ("Pembeli" & Integer'Image (K) & ": ");
Jual_Satu_Tiket;
end loop;
Put_Line ("Sisa tiket akhir:" & Natural'Image (Sisa_Tiket));
end Loket_Antrean;# kompilasi program
gnatmake -q -gnata loket_antrean.adb
# jalankan program hasil kompilasi
./loket_antreanPembeli 1: Tiket terjual, sisa 2
Pembeli 2: Tiket terjual, sisa 1
Pembeli 3: Tiket terjual, sisa 0
Pembeli 4: Penjualan dihentikan: tiket telah habis
Sisa tiket akhir: 0Pola when E : Constraint_Error => memberi nama pada kejadian exception, sehingga pesannya dapat dibaca dengan Exception_Message (E). Pesan yang dibawa klausa with pada raise muncul utuh pada keluaran, sedangkan exception bawaan yang dibangkitkan tanpa pesan biasanya menyertakan penunjuk berkas dan baris. Perhatikan pula bahwa program tidak berhenti, karena setiap pemanggilan prosedur memulai siklus penanganan yang baru.
Kesalahan umum#
- Menyangka eksekusi kembali ke titik error. Handler tidak melanjutkan pernyataan yang gagal, melainkan mengalihkan eksekusi ke pernyataan setelah blok. Perbaikannya, letakkan pekerjaan setelah pemulihan tepat di bawah blok tersebut, atau bungkus percobaan dalam perulangan jika percobaan ulang memang diinginkan.
- Menggunakan exception sebagai kontrol alur biasa. Percabangan yang dapat dinyatakan dengan
ifsebaiknya tidak ditulis sebagai pasanganraisedan penangkapnya, karena alur program menjadi sulit diikuti dan biaya eksekusinya lebih besar. Perbaikannya, gunakan exception untuk kejadian luar biasa yang melanggar asumsi program. - Membangkitkan ulang dengan bentuk yang keliru. Di dalam handler, pernyataan
raisetanpa nama membangkitkan ulang exception yang sedang ditangani, sedangkanraise Xmembangkitkan exception baru yang kehilangan kejadian aslinya. Perbaikannya, gunakan bentuk tanpa nama ketika kejadian asli ingin dipertahankan.
Ringkasan#
- Exception memutus aliran eksekusi, dan handler pada blok atau badan subprogram menangkapnya berdasarkan nama exception.
- Eksekusi tidak kembali ke titik error, melainkan berlanjut dari pernyataan setelah blok, sehingga pemulihan berarti menjaga keadaan program tetap konsisten.
raise X with "pesan"membangkitkan exception dengan pesan, dan handlerwhen E : X =>membaca pesannya melaluiAda.Exceptions.Exception_Message (E).
Referensi#
- Introduction to Ada: Exceptions — AdaCore — Bab kursus resmi yang membahas deklarasi exception, pernyataan raise, dan penanganannya.
- Guidelines for Safe and Secure Ada/SPARK — AdaCore — Panduan resmi yang menjelaskan bahaya cabang when others tanpa penanganan yang sungguh-sungguh.