Exception

Mekanisme exception, penanganan Constraint_Error, dan pemulihan yang disengaja.

Daftar isi

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.

ExceptionKondisi yang memicunya
Constraint_Errorpelanggaran kendala tipe, misalnya nilai di luar rentang atau indeks di luar batas array
Program_Errorpelanggaran aturan struktur program
Storage_Errormemori yang diminta tidak tersedia
Tasking_Errorkomunikasi 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.

ada Bentuk penanganan exception pada blok
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.

ada pulih_dari_error.adb
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;
bash
# kompilasi program
gnatmake -q -gnata pulih_dari_error.adb
# jalankan program hasil kompilasi
./pulih_dari_error
text Keluaran
Kuantitas awal: 4
Penugasan dibatalkan: nilai 99 di luar rentang 1 .. 10
Program berlanjut, Kuantitas tetap: 4

Baris 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.

ada loket_antrean.adb
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;
bash
# kompilasi program
gnatmake -q -gnata loket_antrean.adb
# jalankan program hasil kompilasi
./loket_antrean
text Keluaran
Pembeli 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: 0

Pola 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 if sebaiknya tidak ditulis sebagai pasangan raise dan 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 raise tanpa nama membangkitkan ulang exception yang sedang ditangani, sedangkan raise X membangkitkan 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 handler when E : X => membaca pesannya melalui Ada.Exceptions.Exception_Message (E).

Referensi#