Bab.
12 Penanganan Eksepsi
12.1 Introduksi
Error runtime terjadi pada saat suatu program sedang berjalan dan JVM
mendeteksi suatu operasi yang mustahil dilakukan. Misalnya, jika Anda mencoba
mengakses suatu array menggunakan suatu indeks di luar rentang yang tersedia,
maka program akan mendapatkan suatu error runtime
dengan ArrayIndexOutOfBoundsException.
Untuk membaca data dari file, Anda perlu menciptakan suatu objek Scanner menggunakan new(Scanner new File (namafile)). Jika
file tidak ada, program Anda akan mendapatkan suatu error runtime dengan FileNotFoundException.
Dalam JAVA, setiap error runtime diakibatkan oleh eksepsi.
Eksepsi merupakan suatu objek yang merepresentasikan suatu error atau suatu
kondisi yang dapat mencegah eksekusi berjalan secara normal. Jika eksepsi tidak
diatasi, maka program akan berhenti secara tidak normal. Bagaimana Anda
menangani eksepsi sehingga program dapat tetap berjalan atau berhenti secara
normal? Inilah topik yang akan dibahas dalam bab ini.
12.2 Sekilas Tentang Penanganan
Eksepsi
Untuk mendemonstrasikan bagaimana
menangani eksepsi, termasuk bagaimana suatu objek eksepsi diciptakan dan
dilempar, berikut disajikan suatu contoh (kode12.1) yang membaca dua integer
dan menampilkan hasil pembagiannya (tanpa sisa).
Kode12.1 HasilBagi.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
import java.util.Scanner;
public class HasilBagi {
public static void main(String[]
args) {
Scanner masukan = new
Scanner(System.in);
// Meminta pengguna untuk memasukkan dua
integer
System.out.print("Masukkan dua
integer: ");
int angka1 = masukan.nextInt();
int angka2 = masukan.nextInt();
System.out.println(angka1 + " / "
+ angka2 + " adalah " +
(angka1 / angka2));
}
}
|
Keluaran
Masukkan dua
integer: 5 3
5 / 3 adalah
1
Masukkan dua
integer: 3 0
Exception in
thread "main" java.lang.ArithmeticException: / by zero
at HasilBagi.main(HasilBagi.java:12)
Jika Anda memasukkan 0 pada integer kedua, suatu
error runtime akan terjadi, karena
Anda tidak bisa membagi suatu integer oleh 0. Cara sederhana untuk membetulkan
error ini adalah dengan menambahkan statemen if untuk menguji angka kedua, seperti ditampilkan pada kode13.2.
Kode12.2 HasilBagiDenganIf.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
import java.util.Scanner;
public class HasilBagi {
public static void main(String[]
args) {
Scanner masukan = new
Scanner(System.in);
// Meminta pengguna untuk memasukkan dua
integer
System.out.print("Masukkan dua
integer: ");
int angka1 = masukan.nextInt();
int angka2 = masukan.nextInt();
if (angka2 != 0)
System.out.println(angka1 + " /
" + angka2 + " adalah " +
(angka1 / angka2));
else
System.out.println("Pembagi
tidak boleh nol ");
}
}
|
Keluaran:
Masukkan dua
integer: 3 0
Pembagi
tidak boleh nol
Untuk mendemonstrasikan konsep penanganan
eksepsi, termasuk bagaimana menciptakan, melempar, menangkap, dan menangani
suatu eksepsi, kode12.2 ditulis-ulang yang ditampilkan pada kode12.3.
Kode12.3 HasilBagiDenganEksepsi.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
import java.util.Scanner;
public class HasilBagiDenganEksepsi {
public static void main(String[]
args) {
Scanner masukan = new
Scanner(System.in);
// Meminta pengguna memasukkan dua
integer
System.out.print("Masukkan dua
integer: ");
int angka1 = masukan.nextInt();
int angka2 = masukan.nextInt();
try {
if (angka2 == 0)
throw new
ArithmeticException("Pembagi tidak boleh nol");
System.out.println(angka1 + " /
" + angka2 + " adalah " +
(angka1 / angka2));
}
catch (ArithmeticException ex) {
System.out.println("Eksepsi:
suatu integer " +
"tidak bisa dibagi oleh nol
");
}
System.out.println("Eksekusi
berlanjut ...");
}
}
|
Keluaran:
Masukkan dua
integer: 3 0
Eksepsi:
suatu integer tidak bisa dibagi oleh nol
Eksekusi
berlanjut ...
Masukkan dua
integer: 3 5
3 / 5 adalah
0
Eksekusi
berlanjut ...
Program memuat suatu blok if dan suatu blok catch. Blok try (baris
12-18) memuat kode yang dieksekusi dalam situasi normal. Blok catch (baris 19-22) memuat kode yang
dieksekusi ketika angka2 bernilai 0.
Pada situasi ini, program melemparkan suatu eksepsi dengan mengeksekusi
throw new ArithmeticException("Pembagi tidak boleh nol");
Nilai yang dilemparkan, pada kasus ini new ArithmeticException("Pembagi
tidak boleh nol"), disebut dengan eksepsi. Eksekusi atau suatu
statemen throw disebut dengan pelemparan suatu eksepsi. Eksepsi merupakan
suatu objek yang diciptakan dari suatu kelas eksepsi. Pada kasus ini, kelas
eksepsinya adalah java.lang.ArithmeticException.
Ketika suatu eksepsi dilempar, aliran
eksekusi normal diinterupsi. Eksepsi kemudian ditangkap oleh blok catch. Kode di dalam blok catch dieksekusi untuk menangani
eksepsi. Setelah itu, statemen (baris 24) setelah blok catch dieksekusi.
Statemen throw mirip dengan suatu pemanggilan metode, namun perbedaannya
adalah statemen throw tidak
memanggil suatu metode, melainkan memanggil suatu blok catch. Pada kasus ini, blok catch
seperti suatu definisi metode dengan suatu parameter yang cocok dengan tipe
nilai yang sedang dilempar. Tidak seperti metode, setelah blok catch dieksekusi, kendali program tidak
kembali kepada statemen throw,
melainkan kepada statemen setelah blok catch.
Pengenal ex di dalam header blok catch
catch (ArithmeticException
ex)
berperan menyerupai parameter di dalam
suatu metode. Jadi, parameter ini disebut dengan parameter block catch. Tipe (dalam hal ini, ArithmeticException) sebelum pengenal ex menspesifikasi jenis eksepsi yang
dapat ditangkap oleh blok catch.
Setelah suatu eksepsi ditangkap oleh catch,
Anda bisa mengakses nilai yang dilempar dari parameter ex dalam tubuh suatu blok catch.
Kesimpulannya, template untuk suatu blok try-throw-catch adalah
seperti ini:
try
{
Kode untuk try;
Melempar suatu eksepsi dengan suatu statemen
throw atau
dari metode jika perlu;
Kode lain untuk try;
}
catch
(tipe ex) {
Kode untuk memproses eksepsi;
}
12.3 Kelebihan Penanganan Eksepsi
Anda telah melihat pada kode12.3 bagaimana
suatu eksepsi diciptakan, dilempar, ditangkap, dan diatasi. Anda mungkin
bertanya-tanya tentang keuntungannya. Untuk melihat keuntungannya, kode12.3
ditulis-ulang untuk menghitung suatu hasil bagi (tanpa sisa) menggunakan suatu
metode, seperti yang ditunjukkan pada kode12.4 sebagai berikut:
Kode12.4 HasilBagiDenganEksepsi.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
import java.util.Scanner;
public class HasilBagiDenganMetode {
public static int hasilBagi(int angka1, int angka2)
{
if
(angka2 == 0)
throw new
ArithmeticException("Pembagi tidak boleh nol");
return
angka1 / angka2;
}
public
static void main(String[] args) {
Scanner
masukan = new Scanner(System.in);
//
Meminta pengguna memasukkan dua integer
System.out.print("Masukkan
dua integer: ");
int
angka1 = masukan.nextInt();
int
angka2 = masukan.nextInt();
try {
int hasil = hasilBagi(angka1,
angka2);
System.out.println(angka1
+ " / " + angka2 + " adalah "
+
hasil);
}
catch (ArithmeticException ex) {
System.out.println("Eksepsi:
suatu integer " +
"tidak
dapat dibagi oleh nol ");
}
System.out.println("Eksekusi
berlanjut ...");
}
}
|
Keluaran:
Masukkan dua
integer: 5 3
5 / 3 adalah
1
Eksekusi
berlanjut ...
Masukkan dua
integer: 3 0
Eksepsi:
suatu integer tidak dapat dibagi oleh nol
Eksekusi
berlanjut ...
Metode hasilBagi
(baris 4-9) menghasilkan hasil bagi (tanpa sisa) atau dua integer. Jika angka2 bernilai 0, maka metode tidak
tersebut tidak bisa menghasilkan nilai balik. Jadi, eksepsi dilempar pada baris
6.
Metode utama memanggil hasilBagi (baris 20). Jika metode hasilBagi dieksekusi secara normal, maka terdapat hasil balik yang
dikembalikan kepada pemanggil. Jika metode hasilBagi
mengalami eksepsi, maka eksepsi dilempar kembali kepada pemanggil. Blok catch dari pemanggil akan menangani
eksepsi tersebut.
Sekarang Anda melihat apa keuntungan
penanganan eksepsi. Hal ini memampukan suatu metode untuk melempar suatu
eksepsi kepada pemanggil. Pemanggil yang akan menangani eksepsi tersebut. Tanpa
kapabilitas ini, metode yang dipanggil itu sendiri yang menangani eksepsi atau harus
keluar dari program. Seringkali metode yang dipanggil tidak tahu harus
bagaimana ketika error terjadi. Hal ini umum terjadi pada metode-metode
pustaka. Metode pustaka dapat mendeteksi error, tetapi hanya pemanggillah yang
tahu apa yang perlu dilakukan ketika suatu error terjadi. Keuntungan yang
paling penting dalam penanganan eksepsi adalah pemisahan antara pendeteksian
error (dilakukan di dalam suatu metode yang dipanggil) dengan penanganan error
(dilakukan di dalam metode pemanggil).
Banyak metode pustakan melempar eksepsi.
Kode12.5 menyajikan suatu contoh yang menangani FileNotFoundException dalam memanggil konstruktor Scanner(File file).
Kode12.5 DemoFileNotFoundException.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
import java.util.Scanner;
import java.io.*;
public class DemoFileNotFoundException {
public
static void main(String[] args) {
Scanner
masukanDariKonsol = new Scanner(System.in);
//
Meminta pengguna memasukkan suatu nama file
System.out.print("Masukkan
suatu nama file: ");
String
namafile = masukanDariKonsol.nextLine();
try {
Scanner masukanDariFile = new
Scanner(new File(namafile));
System.out.println("File
" + namafile + " ada ");
//
Memproses file...
}
catch (FileNotFoundException ex) {
System.out.println("Eksepsi:
" + namafile + " tidak ada");
}
}
}
|
Keluaran:
Masukkan
suatu nama file: E:\Cuaca.java
File
E:\Cuaca.java ada
Masukkan
suatu nama file: E:\buku.java
Eksepsi:
E:\buku.java tidak ada
Program menciptakan suatu Scanner untuk suatu file (baris 12).
Jika file tidak ada, konstruktor melempar suatu FileNotFoundException, yang ditangkap dalam blok catch.
Kode12.6 memberikan suatu contoh yang
menangani suatu eksepsi InputMismatchException.
Kode12.6 DemoInputMismatchException.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
import java.util.*;
public class DemoInputMismatchException {
public
static void main(String[] args) {
Scanner
masukan = new Scanner(System.in);
boolean
masukanLanjut = true;
do
{
try {
System.out.print("Masukkan suatu integer: ");
int angka = masukan.nextInt();
// Menampilkan hasil
System.out.println(
"Angka yang dimasukkan adalah " + angka);
masukanLanjut = false;
}
catch (InputMismatchException ex) {
System.out.println("Coba lagi. (" +
"Masukan tidak tepat: yang dibutuhkan adalah suatu integer)");
masukan.nextLine(); // Buang masukan
}
} while
(masukanLanjut);
}
}
|
Keluaran:
Masukkan
suatu integer: 3.6
Coba lagi.
(Masukan tidak tepat: yang dibutuhkan adalah suatu integer)
Masukkan
suatu integer: ab
Coba lagi.
(Masukan tidak tepat: yang dibutuhkan adalah suatu integer)
Masukkan
suatu integer: 5
Angka yang
dimasukkan adalah 5
Ketika mengeksekusi masukan.nextInt() (baris 11), suatu InputMismatchException terjadi jika masukan yang diberikan bukan
suatu integer. Misalnya, 3.6 yang dimasukkan. suatu InputMismatchException terjadi dan kendali dipindahkan kepada blok catch. Statemen-statemen yang ada dalam
blok catch sekarang dieksekusi.
Statemen masukan.nextLine() pada
baris 22 membuang baris masukan saat ini sehingga pengguna dapat memasukkan
suatu baris masukan baru. Variabel masukanLanjut
mengendalikan loop. Nilai awalnya adalah true
(baris 6), dan diubah menjadi false
(baris 17) ketika masukan valid.
12.4 Tipe - Tipe Eksepsi
Beberapa tipe eksepsi yang telah digunakan
dalam bagian-bagian terdahulu adalah ArithmeticException,
FileNotFoundException, dan InputMismatchException. Apakah ada tipe
eksepsi yang lain? Ya, ada. Terdapat banyak kelas eksepsi yang terdefinisi di
dalam JAVA API. Gambar 12.1 menunjukkan beberapa diantaranya.
Gambar 12.1 Eksepsi-eksepsi yang dilempat merupakan
instans-instans kelas yang ditunjukkan dalam diagram ini, atau sub-subkelas
dari salah satu kelas ini.
Kelas Throwable
merupakan akar dari semua kelas eksepsi. Semua kelas eksepsi JAVA mewarisi
secara langsung atau tidak langsung dari Throwable.
Anda bisa menciptakan kelas eksepsi sendiri dengan cara mewarisi Exception atau sub-subkelas Exception.
Kelas-kelas eksepsi dapat diklasifikasikan
menjadi tiga tipe utama: error sistem, eksepsi, dan eksepsi runtime.
·
Error sistem dilemparkan oleh
JVM dan direpresentasikan oleh kelas Error.
Kelas Error mendeskripsikan error
internal. Error semacam ini jarang terjadi. Jika terjadi, sangat terbatas yang
dapat Anda lakukan kecuali hanya memberitahu pengguna dan mencoba mengentikan
program secara normal. Beberapa contoh sub-subkelas Error dicantumkan pada Tabel 12.1.
Tabel 12.1 Dua contoh sub-subkelas Error
Kelas
|
Alasan yang mungkin terjadinya eksepsi
|
LinkageError
VirtualMachineError
|
Suatu kelas
memiliki beberapa ketergantungan pada kelas lain, tetapi kelas lain ini telah
diubah tanpa menjaga kompatibilitasnya setelah kompilasi dilakukan terhadap
kelas pertama.
JVM telah
kehabisan sumber-daya yang dibutuhkan untuk melanjutkan operasi.
|
·
Eksepsi direpresentasikan
dalam kelas Exception, yang
mendeskripsikan error-error yang diakibatkan oleh program Anda dan oleh
lingkungan luar. Error-error ini ditangkap dan ditangani oleh program Anda.
Beberapa contoh subkelas dari Exception
dicantumkan pada Tabel 12.2 berikut ini:
Tabel 12.2 Dua contoh sub-subkelas Exception
Kelas
|
Alasan yang mungkin terjadinya eksepsi
|
ClassNotFoundException
IOException
|
Percobaan untuk
menggunakan suatu kelas yang tidak ada. Eksepsi ini akan terjadi, misalnya,
jika Anda mencoba menjalankan suatu kelas yang tidak ada menggunakan perintah
java, atau jika program Anda
terdiri-dari, katakanlah, tiga file kelas, namun hanya dua saja yang dapat
ditemukan.
Berkaitan dengan
operasi masukan/keluaran, seperti masukan yang tidak valid, membaca melampaui
akhir suatu file, dan membuka file yang tidak ada. Beberapa sub-subkelas IOException adalah InterruptedIOException, EOFException (EOF adalah singkatan
dari end of file), dan FileNotFoundException.
|
·
Eksepsi runtime direpresentasikan
oleh kelas RuntimeException, yang
mendeskripsikan kesalahan pemrograman, seperti casting yang salah, pengaksesan
array di luar batas, dan kesalahan numerik. Eksepsi runtime biasanya dilempar
oleh JVM. Beberapa sub-subkelas RuntimeException
dicantumkan pada Tabel 12.3.
Tabel 12.3 Dua contoh sub-subkelas Exception
Kelas
|
Alasan yang mungkin terjadinya eksepsi
|
ArithmeticException
NullPointerException
IndexOutOfBoundsException
IllegalArgumentException
|
Pembagian suatu
integer oleh nol.
Mencoba untuk
mengakses suatu objek melalui suatu variabel referensi null.
Indeks array di
luar rentang yang ada.
Argumen yang
dilewatkan kepada suatu metode adalah ilegal atau tidak cocok.
|
12.5 Lebih Lanjut Tentang
Penanganan Eksepsi
Beberapa bagian terdahulu telah menyajikan
kepada Anda pengenalan tentang bagaimana menangani eksepsi dan tentang
tipe-tipe eksepsi yang terdefinisi dalam JAVA. Bagian ini akan memberikan
diskusi yang lebih dalam tentang penanganan eksepsi.
Model penanganan eksepsi dalam JAVA
didasarkan pada tiga operasi: pendeklarasian suatu eksepsi, pelemparan suatu
eksepsi, dan penangkapan suatu eksepsi, seperti yang ditampilkan pada Gambar
12.2 sebagai berikut:
Gambar 12.2 Penanganan eksepsi dalam JAVA didasarkan
pada tiga operasi: pendeklarasian suatu eksepsi, pelemparan suatu eksepsi, dan
penangkapan suatu eksepsi.
12.5.1 Mendeklarasikan Eksepsi
Dalam JAVA, statemen yang sedang dieksekusi
berada dalam suatu metode. Interpreter JAVA memanggil metode main untuk memulai pengeksekusian
program. Setiap metode harus menyatakan tipe eksepsi yang akan dilempar. Hal
ini dikenal dengan pelemparan eksepsi.
Karena error sistem dan error runtime
bisa terjadi pada sembarang kode, JAVA tidak mensyaratkan Anda untuk
mendeklarasikan Error dan RuntimeException secara eksplisit dalam
metode. Namun, semua eksepsi lain yang akan dilemparkan oleh metode harus
dideklarasikan secara eksplisit pada header metode sehingga pemanggil metode
diberitahu tentang jenis eksepsi yang bakal terjadi.
Untuk mendeklarasikan suatu eksepsi di
dalam suatu metode, gunakan katakunci throws
pada header metode, seperti contoh ini:
public void metodeKu() throws
IOException
Katakunci throws mengindikasikan bahwa metodeKu
mungkin akan melempar suatu IOException.
Jika metode kemungkinan akan melempar beberapa eksepsi, maka tambahkan daftar
eksepsi, dipisahkan dengan koma, setelah throws:
public
void metodeKu()
throws Eksepsi1, Eksepsi2, ..., EksepsiN
12.5.2 Melempar Eksepsi
Suatu program yang mendeteksi suatu error
dapat menciptakan suatu instans dari tipe eksepsi yang cocok dan
melemparkannya. Ini dikenal dengan pelemparan
eksepsi. Berikut adalah salah satu contoh. Dimisalkan program mendeteksi
bahwa suatu argumen yang dilewatkan kepada metode tidak mematuhi kontrak metode
(misalnya, argumen harus tidak negatif, tetapi yang dilewatkan suatu argumen
negatif); maka program menciptakan suatu instans dari IllegalArgumentException dan melemparkannya, sebagai berikut:
IllegalArgumentException
ex =
new IllegalArgumentException("Argumen salah");
throw ex;
atau, Anda bisa menggunakan ini:
throw
new IllegalArgumentException("Argumen
salah ");
12.5.3 Menangkap Eksepsi
Anda sekarang telah mengetahui bagaimana
mendeklarasikan dan melemparkan suatu eksepsi. Ketika suatu eksepsi dilempar,
eksepsi itu dapat ditangkap dan ditangani di dalam suatu blok try-catch, sebagai berikut:
try
{
statemen-statemen;
// Statemen yang mungkin melempar eksepsi
}
catch
(Eksepsi1
exVar1) {
statemen untuk mengatasi eksepsi1;
}
catch
(Eksepsi2
exVar2) {
statemen untuk mengatasi eksepsi2;
}
...
catch
(EksepsiN
exVarN) {
statemen untuk mengatasi eksepsiN;
}
Jika tidak terdapat eksepsi selama eksekusi
blok try, maka blok-blok catch akan dilompati.
Jika salah satu statemen di dalam blok try melemparkan suatu eksepsi, maka
JAVA melompati statemen-statemen yang tersisa di dalam blok try dan mulai mencari kode untuk
menangani eksepsi tersebut. Kode yang menangani eksepsi disebut dengan exception handler; ditemukan dengan
mempropagasi eksepsi ke belakang melalui rantai pemanggilan metode, mulai dari
metode saat ini. Setiap blok catch
akan diuji secara bergiliran, dari pertama sampai terakhir, untuk melihat
apakah tipe objek eksepsi adalah instans dari kelas eksepsi dalam blok catch. Jika benar, objek eksepsi
ditugaskan kepada variabel yang dideklarasikan, dan kemudian kode di dalam blok
catch dieksekusi. Jika tidak ada
handler ditemukan, maka JAVA keluar dari metode ini, melewatkan eksepsi kepada
metode pemanggil, dan melanjutkan proses yang sama untuk menemukan suatu
handler. Jika tidak ada satupun handler yang ditemukan dalam rantai metode,
maka program akan berhenti dan menampilkan suatu pesan error pada konsol.
Proses pencarian suatu handler disebut dengan penangkapan suatu eksepsi.
Dimisalkan metode main memanggil metode1, metode1 memanggil metode2, metode2
memanggil metode3, dan metode3 melemparkan suatu eksepsi,
seperti ditunjukkan pada Gambar 12.3. Perhatikan skenario berikut ini:
·
Jika tipe eksepsi adalah Eksepsi3, maka akan ditangkap oleh blok
catch untuk menangani eksepsi ex3 dalam metode2. statemen5
dilompati dan statemen6 dieksekusi.
·
Jika tipe eksepsi adalah Eksepsi2, maka metode2 dibatalkan, kendali program dikembalikan kepada metode1, dan eksepsi ditangkap oleh
blok catch untuk menangani eksepsi ex2 dalam metode1. statemen3
dilompati, dan statemen4 dieksekusi.
·
Jika tipe eksepsi adalah Eksepsi1, maka metode1 dibatalkan, kendali program dikembalikan kepada main, dan eksepsi ditangkap oleh blok catch untuk menangani eksepsi ex1 dalam main. statemen1
dilompati, dan statemen2 dieksekusi.
·
Jika tipe eksepsi tidak ditangkap dalam metode1, metode2, dan main, maka
program akan berhenti. statemen1 dan
statemen2 tidak dieksekusi.
Gambar 12.3 Jika suatu eksepsi tidak ditangkap dalam
metode saat ini, maka eksepsi tersebut dilemparkan kepada pemanggil. Proses
berulang sampai eksepsi ditangkap atau dilewatkan kepada metode main.
12.5.4 Memperoleh Informasi dari
Eksepsi
Suatu objek eksepsi memuat informasi
berguna tentang eksepsi. Anda dapat menggunakan metode-metode instans dalam
kelas java.lang.Throwable berikut
ini untuk mendapatkan informasi yang berkaitan dengan eksepsi, seperti yang
ditampilkan pada Gambar 12.4. Metode printStackTrace()
menampilkan jejak tumpukan informasi pada konsol. Metode getStackTrace() menyediakan akses kepada jejak tumpukan yang
ditampilkan oleh printStackTrace().
Gambar 12.4 Throwable
merupakan kelas akar bagi semua objek eksepsi
Kode12.7 menyajikan suatu contoh yang
menggunakan metode-metode di dalam kelas Throwable
untuk menampilkan informasi eksespi.
Baris 4 memanggil metode jum untuk
mengembalikan penjumlahan semua elemen di dalam array. Terdapat suatu error
pada baris 23 yang menyebabkan ArrayIndexOutOfBoundsException,
suatu subkelas dari IndexOutOfBoundsException.
Eksepsi ini ditangkap dalam suatu blok try-catch. Baris 7-9 menampilkan jejak
tumpukan, pesan eksepsi, dan pesan dan objek eksepsi menggunakan printStackTrace(), getMessage(), dan toString(),
seperti yang ditunjukkan pada Gambar 12.5. Baris 10 membawa elemen-elemen jejak
tumpukan ke dalam suatu array. Setiap elemen merepresentasikan suatu
pemanggilan metode. Anda dapat memperoleh metode (baris 12), nama kelas (baris
13), dan jumlah baris eksepsi (baris 14) untuk setiap elemen.
Gambar 12.5 Anda dapat menggunakan printStackTrace(), getMessage(),toString(),
dan getStackTrace() untuk
mendapatkan informasi dari objek eksepsi.
Kode12.7 UjiEksepsi.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
public class UjiEksepsi {
public
static void main(String[] args) {
try
{
System.out.println(jum(new int[] {1, 2,
3, 4, 5}) );
}
catch
(Exception ex) {
ex.printStackTrace();
System.out.println("\n"
+ ex.getMessage());
System.out.println("\n"
+ ex.toString());
System.out.println("\nInfo
jejak tumpukan dari getStackTrace");
StackTraceElement[]
elemenJejak = ex.getStackTrace();
for
(int i = 0; i < elemenJejak.length; i++) {
System.out.print("metode " +
elemenJejak[i].getMethodName());
System.out.print("(" + elemenJejak[i].getClassName() +
":");
System.out.println(elemenJejak[i].getLineNumber() + ")");
}
}
}
private
static int jum(int[] list) {
int
hasil = 0;
for
(int i = 0; i <= list.length; i++)
hasil
+= list[i];
return
hasil;
}
}
|
12.5.5 Contoh: Mendeklarasikan,
Melempar, dan Menangkap Eksepsi
Contoh ini mendemonstrasikan
pendeklarasian, pelemparan, dan penangkapan eksepsi dengan memodifikasi metode tetapkanRadius dalam kelas Lingkaran pada kode8.9, Lingkaran3.java. Metode tetapkanRadius yang baru melemparkan
suatu eksepsi jika radius bernilai negatif.
Kelas Lingkaran
akan dinamai-ulang menjadi LingkaranDenganEksepsi
yang diberikan pada kode 12.8. Kelas ini sama dengan kelas Lingkaran kecuali bahwa metode tetapkanRadius(double
radiusBaru) melemparkan suatu IllegalArgumentException
jika argumen radiusBaru bernilai
negatif.
Kode12.8 LingkaranDenganEksepsi.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
public class LingkaranDenganEksepsi {
/**
Radius lingkaran */
private double radius = 1;
/**
Jumlah objek yang diciptakan */
private
static int jumlahObjek = 0;
/**
Menciptakan suatu lingkaran dengan radius 1 */
public
LingkaranDenganEksepsi() {
this(1.0);
}
/**
Menciptakan suatu lingkaran dengan radius tertentu */
public
LingkaranDenganEksepsi(double radiusBaru) {
tetapkanRadius(radiusBaru);
jumlahObjek++;
}
/**
Memberikan nilai balik radius */
public
double dapatRadius(){
return
radius;
}
/**
Menetapkan nilai radius baru */
public
void tetapkanRadius(double radiusBaru)
throws IllegalArgumentException {
if (radiusBaru >= 0)
radius
= radiusBaru;
else
throw new IllegalArgumentException(
"Radius tidak boleh
negatif");
}
/** Mengembalikan
jumlahObjek */
public
static int dapatJumlahObjek(){
return
jumlahObjek;
}
/**
Mengembalikan luas lingkaran */
public
double dapatLuas() {
return
radius * radius * Math.PI;
}
}
|
Suatu program uji yang menggunakan kelas Lingkaran baru ini diberikan pada
kode12.9.
Kode12.9 UjiLingkaranDenganEksepsi.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public class UjiLingkaranDenganEksepsi {
public static void main(String[] args) {
try {
LingkaranDenganEksepsi
c1 = new LingkaranDenganEksepsi(5);
LingkaranDenganEksepsi
c2 = new LingkaranDenganEksepsi(-5);
LingkaranDenganEksepsi
c3 = new LingkaranDenganEksepsi(0);
}
catch (IllegalArgumentException
ex) {
System.out.println(ex);
}
System.out.println("Jumlah
objek yang diciptakan: " +
LingkaranDenganEksepsi.dapatJumlahObjek());
}
}
|
Keluaran:
java.lang.IllegalArgumentException:
Radius tidak boleh negatif
Jumlah objek
yang diciptakan: 1
Kelas Lingkaran
yang asli tetap utuh kecuali bahwa nama kelas diubah menjadi LingkaranDenganEksepsi, suatu
konstruktor baru LingkaranDenganEksepsi(radiusBaru)
diciptakan, dan metode tetapkanRadius
sekarang mendeklarasikan suatu eksepsi dan melemparkannya jika radius bernilai
negatif.
Metode tetapkanRadius melempar IllegalArgumentException pada header
metode (baris 25-32 dalam LingkaranDenganEksepsi.java). Kelas LingkaranDenganEksepsi sekarang masih dapat dikompilasi meski jika
klausa IllegalArgumentException
dihilangkan dari deklarasi metode, karena merupakan subkelas dari RuntimeException dan setiap metode
dapat melempar RuntimeException
meskipun tidak dideklarasikan pada header metode.
Program uji menciptakan tiga objek LingkaranDenganEksepsi, c1, c2, dan c3, untuk
menguji bagaimana program menangani eksepsi. Pemanggilan new LingkaranDenganEksepsi(-5) (baris 5 pada kode12.9) menyebabkan
metode tetapkanRadius dipanggil,
yang melemparkan IllegalArgumentException,
karena radius bernilai negatid. Pada blok catch,
tipe objek ex adalah IllegalArgumentException, yang sesuai
dengan objek eksepsi yang dilemparkan oleh metode tetapkanRadius. Jadi, eksepsi ini berhasil ditangkap oleh blok catch.
Handler eksepsi menampilkan suatu pesan
singkat, ex.toString() (baris 9),
tentang eksepsi, menggunakan System.out.println(ex).
Perhatikan bahwa eksekusi tetap berlanjut
meskipun eksepsi terjadi. Jika handler tidak bisa menangkap eksepsi, maka
program akan berhenti secara mendadak.
Program uji masih tetap dapat dikompilasi
meski bila statemen try tidak
digunakan, karena metode melemparkan suatu instans dari IllegalArgumentException, yang merupakan subkelas dari RuntimeException. Jika suatu metode
melemparkan selain RuntimeException dan Error, maka metode harus dipanggil di
dalam blok try-catch.
12.6 Klausa finally
Kadang-kala, Anda menginginkan kode untuk
dieksekusi tanpa mempedulikan apakah suatu eksepsi ditangkap atau tidak. JAVA
memiliki suatu klausa finally yang
dapat digunakan untuk mencapai tujuan ini. Sintaks klausa finally adalah seperti ini:
try
{
statemen-statemen;
}
catch
(Eksepsi ex)
{
penanganan ex;
}
finally
{
statemen-statemen akhir;
}
Kode di dalam blok finally dieksekusi pada situasi apapun, tanpa memandang apakah
eksekusi terjadi di dalam blok try
ditangkap atau tidak. Perhatikan tiga kemungkinan kasus berikut ini:
·
Jika tidak ada eksepsi yang di dalam
blok try, maka statemen-statemen akhir dieksekusi, dan statemen selanjutnya
setelah statemen try dieksekusi.
·
Jika suatu statemen menyebabkan eksepsi
di dalam blok try yang ditangkap
dalam blok catch, maka sisa statemen
dalam di dalam blok try dilompati,
blok catch dieksekusi, klausa finally dieksekusi. Statemen berikutnya
setelah statemen try dieksekusi.
·
Jika salah satu statemen menyebabkan
eksepsi di dalam blok try yang tidak
ditangkap dalam sembarang blok catch,
maka statemen-statemen lain di dalam blok try
dilompati, klausa finally dieksekusi,
dan eksepsi dilewatkan kepada metode pemanggil.
Blok finally
dieksekusi meskipun jika terdapat statemen return sebelum mencapai blok finally. Penggunaan finally yang umum dilakukan adalah
dalam pemrograman I/O. Untuk menjamin bahwa suatu file ditutup, maka Anda bisa
menempatkan statemen penutupan file di dalam blok finally, seperti yang ditunjukkan pada kode12.10.
Kode12.10 DemoFinally.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
public class DemoFinally {
public
static void main(String[] args) {
java.io.PrintWriter
keluaran = null;
try {
//
Menciptakan suatu file
keluaran = new
java.io.PrintWriter("teks.txt");
//
Menulis keluaran terformat pada file
keluaran.println("JAVA
itu Tangguh!");
}
catch (java.io.IOException ex) {
ex.printStackTrace();
}
finally {
//
Menutup
if (keluaran != null)
keluaran.close();
}
System.out.println("Akhir
program");
}
}
|
Statemen pada baris 7 dan 10 bisa jadi
melemparkan suatu IOException,
sehingga keduanya ditempatkan dalam blok suatu try. Statemen keluaran.close()
menutup objek printWriter
12.7 Kapan Menggunakan Eksepsi
Suatu eksepsi terjadi di dalam metode. Jika
Anda ingin eksepsi diproses oleh pemanggilnya belakangan, maka Anda harus
menciptakan suatu objek eksepsi dan melemparkannya. Jika Anda menangani eksepsi
di dalam metode, maka tidak ada kebutuhan akan penggunaan dan pelemparan
eksepsi.
Kapan Anda seharusnya menggunakan suatu
blok try-catch di dalam kode? Gunakan ketika Anda harus menghadapi
kondisi-kondisi error yang tak terduga. Jangan gunakan suatu blok try-catch untuk mengatasi situasi-situasi yang sederhana dan bisa
diduga. Sebagai contoh, kode berikut ini
try
{
System.out.println(varRef.toString());
}
catch
(NullPointerException
ex) {
System.out.println("varRef adalah null");
}
lebih baik diganti dengan
if
(varRef!= null)
System.out.println(varRef.toString());
else
System.out.println("varRef is null");
Mana situasi yang luar biasa dan mana
situasi yang terduga kadang-kala sangat susah untuk diputuskan. Intinya adalah
jangan memaksakan untuk menggunakan eksepsi hanya untuk menguji logika
sederhana saja.
12.8 Melempar - Ulang Eksepsi
JAVA mengijinkan handler eksepsi untuk
melempar-ulang eksepsi jika handler tidak dapat memprosesnya atau sekadar
menginginkan pemanggilnya untuk diberitahu akan adanya eksepsi. Sintaks
pelemparan-ulang eksepsi adalah seperti ini:
try
{
statemen-statemen;
}
catch
(Eksepsi ex)
{
melakukan operasi-operasi sebelum keluar;
throw
ex;
}
Statemen throw ex melempar-ulang eksepsi kepada pemanggil sehingga handler
yang lain di dalam pemanggil memiliki kesempatan untuk memproses eksepsi ex.
12.9 Eksepsi Berantai
Pada bagian terdahulu, blok catch dapat melempar-ulang eksepsi
asli. Kadang-kala, Anda menginginkan untuk melemparkan suatu eksepsi baru
(dengan informasi tambahan) bersama dengan eksepsi asli. Hal ini dikenal dengan
eksepsi berantai. Kode12.11 mengilustrasikan
bagaimana menciptakan dan melemparkan eksepsi berantai.
Kode12.11 DemoEksepsiBerantai.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
public class DemoEksepsiBerantai {
public
static void main(String[] args) {
try
{
metode1();
}
catch
(Exception ex) {
ex.printStackTrace();
}
}
public
static void metode1() throws Exception {
try
{
metode2();
}
catch
(Exception ex) {
throw new Exception("Informasi
baru dari metode1", ex);
}
}
public
static void metode2() throws Exception {
throw new Exception("Informasi
baru dari metode2");
}
}
|
Keluaran
java.lang.Exception:
Informasi baru dari metode1
at
DemoEksepsiBerantai.metode1(DemoEksepsiBerantai.java:16)
at
DemoEksepsiBerantai.main(DemoEksepsiBerantai.java:4)
Caused by:
java.lang.Exception: Informasi baru dari metode2
at
DemoEksepsiBerantai.metode2(DemoEksepsiBerantai.java:21)
at
DemoEksepsiBerantai.metode1(DemoEksepsiBerantai.java:13)
... 1 more
Metode main
memanggil metode1 (baris 4), metode1 memanggil metode2 (baris 13), dan metode2
melempar suatu eksepsi (baris 21). Eksepsi ini ditangkap dalam blok catch di dalam metode1 dan kemudian dibungkus menjadi suatu eksepsi bari pada
baris 16. Eksepsi baru tersebut kemudian dilempar dan ditangkap dalam blok catch di dalam metode main pada baris 4. Keluaran menunjukkan
bahwa keluaran dari metode printStackTrace()
pada baris 7. Eksepsi baru yang dilempar dari metode1 ditampilkan pertama kali, diikuti dengan eksepsi asli dari metode2.
12.10 Menciptakan Kelas Eksepsi
Sendiri
JAVA hanya menyediakan sedikit kelas
eksepsi. Anda dapat menggunakannya jika memungkinkan, daripada harus membuat
kelas eksepsi sendiri. Akan tetapi, jika Anda mendapati masalah yang tidak bisa
diselesaikan bila menggunakan kelas-kelas eksepsi dalam pustaka JAVA, maka Anda
bisa menciptakan kelas eksepsi sendiri, yang diderivasi dari Exception atau dari suatu kelas Exception, seperti IOException.
Pada kode12.8, LingkaranDenganEksepsi.java,
metode tetapkanRadius melemparkan
suatu eksepsi jika radius bernilai negatif. Dimisalkan Anda ingin melewatkan
radius kepada handler. Pada kasus itu, Anda bisa menciptakan kelas eksepsi
sendiri, seperti ditunjukkan pada kode12.12.
Kode12.11 DemoEksepsiBerantai.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public class EksepsiRadiusTakSah extends Exception{
private
double radius;
/**
Menciptakan suatu eksepsi */
public EksepsiRadiusTakSah(double
radius){
super("Radius
tidak sah " + radius);
this.radius
= radius;
}
/**
Mengembalikan radius */
public
double dapatRadius() {
return
radius;
}
}
|
Kelas eksepsi buatan sendiri ini mewarisi java.lang.Exception (baris 1). Kelas Exception sendiri mewarisi java.lang.Throwable. Semua metode
(misalnya, getMessage(), toString(), dan printStackTrace()) dalam kelas Exception
diwarisi dari Throwable. Kelas Exception memiliki empat konstruktor.
Dua diantaranya ditampilkan berikut ini:
Baris 6 memanggil konstruktor superkelas
dengan suatu pesan. Pesan ini ditetapkan dalam objek eksepsi dan dapat
diperoleh dengan memanggil metode getMessage()
pada objek.
Untuk menciptakan suatu EksepsiRadiusTakSah, Anda perlu
melewatkan suatu radius. Jadi, metode tetapkanRadius
dalam kode12.8 dapat dimodifikasi menjadi sebagai berikut:
/** Menetapkan suatu radius baru */
public void tetapkanRadius(double radiusBaru) throws EksepsiRadiusTakSah {
if (radiusBaru >= 0)
radius
= radiusBaru;
else
throw new EksepsiRadiusTakSah (radiusBaru);
}
Kode berikut ini menciptakan suatu objek
lingkaran dan menetapkan radiusnya sebesar -5:
try
{
LingkaranDenganEksepsi1 c = new LingkaranDenganEksepsi1(4);
c.tetapkanRadius(-5);
}
catch( ) {
System.out.println("Radius tidak
valid = " + ex.getRadius());
}
Pemanggilan tetapkanRadius(-5) akan melemparkan EksepsiRadiusTakSah, yang ditangkap oleh handler. Handler kemudian
menampilkan radius dalam objek eksepsi ex.
No comments:
Post a Comment