CodeGym /Java Blog /Acak /Pengecualian: penangkapan dan penanganan
John Squirrels
Level 41
San Francisco

Pengecualian: penangkapan dan penanganan

Dipublikasikan di grup Acak
Hai! Saya tidak suka menyebutkannya, tetapi sebagian besar pekerjaan seorang pemrogram berurusan dengan kesalahan. Paling sering, miliknya sendiri. Ternyata tidak ada orang yang tidak melakukan kesalahan. Dan tidak ada program seperti itu juga. Pengecualian: penangkapan dan penanganan - 1 Tentu saja, saat menghadapi kesalahan, hal utama yang harus dipahami adalah penyebabnya. Dan banyak hal yang dapat menyebabkan bug pada suatu program. Pada titik tertentu, pembuat Java bertanya pada diri sendiri apa yang harus dilakukan dengan kesalahan pemrograman yang paling mungkin terjadi? Menghindarinya sepenuhnya tidak realistis, programmer mampu menulis hal-hal yang bahkan tidak dapat Anda bayangkan. :) Jadi, kita perlu memberi bahasa mekanisme untuk bekerja dengan kesalahan. Dengan kata lain, jika ada kesalahan dalam program Anda, Anda memerlukan semacam skrip untuk apa yang harus dilakukan selanjutnya. Apa sebenarnya yang harus dilakukan suatu program ketika terjadi kesalahan? Hari ini kita akan mengenal mekanisme ini. Ini disebut " pengecualian di Jawa ".

Apa itu pengecualian?

Pengecualian adalah situasi luar biasa dan tidak direncanakan yang terjadi saat program sedang berjalan. Ada banyak pengecualian. Misalnya, Anda menulis kode yang membaca teks dari file, dan menampilkan baris pertama.

public class Main {

   public static void main(String[] args) throws IOException {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));
       String firstString = reader.readLine();
       System.out.println(firstString);
   }
}
Tetapi bagaimana jika tidak ada file seperti itu! Program akan menghasilkan pengecualian: FileNotFoundException. Keluaran: Pengecualian di utas "utama" java.io.FileNotFoundException: C:\Users\Username\Desktop\test.txt (Sistem tidak dapat menemukan jalur yang ditentukan) Di Java, setiap pengecualian diwakili oleh kelas terpisah. Semua kelas pengecualian ini berasal dari "leluhur" yang sama— Throwablekelas induk. Nama kelas pengecualian biasanya secara ringkas mencerminkan mengapa pengecualian terjadi:
  • FileNotFoundException(file tidak ditemukan)

  • ArithmeticException(pengecualian terjadi saat melakukan operasi matematika)

  • ArrayIndexOutOfBoundsException(indeks berada di luar batas array). Misalnya, pengecualian ini terjadi jika Anda mencoba menampilkan posisi 23 dari sebuah array yang hanya memiliki 10 elemen.
Secara keseluruhan, Java memiliki hampir 400 kelas seperti itu! Mengapa begitu banyak? Untuk membuatnya lebih nyaman bagi programmer untuk bekerja dengannya. Bayangkan ini: Anda menulis sebuah program, dan saat dijalankan, program tersebut menghasilkan pengecualian yang terlihat seperti ini:

Exception in thread "main"
Uhhhh. :/ Itu tidak banyak membantu. Tidak jelas apa arti kesalahan itu atau dari mana asalnya. Tidak ada informasi yang membantu di sini. Tetapi banyaknya variasi kelas pengecualian di Java memberi programmer apa yang paling penting: jenis kesalahan dan kemungkinan penyebabnya (tertanam dalam nama kelas). Ini hal lain untuk dilihat

Exception in thread "main" java.io.FileNotFoundException: C:\Users\Username\Desktop\test.txt (The system cannot find the specified path)
Segera jelas apa masalahnya dan di mana harus mulai menggali untuk menyelesaikan masalah! Pengecualian, seperti contoh kelas apa pun, adalah objek.

Menangkap dan menangani pengecualian

Java memiliki blok kode khusus untuk bekerja dengan pengecualian: try, catchdan finally. Pengecualian: penangkapan dan penanganan - 2 Kode di mana pemrogram yakin pengecualian dapat terjadi ditempatkan di tryblok. Itu tidak berarti bahwa pengecualian akan terjadi di sini. Artinya, hal itu mungkin terjadi di sini, dan programmer mengetahui kemungkinan ini. Jenis kesalahan yang Anda perkirakan akan terjadi ditempatkan di catchblok. Ini juga berisi semua kode yang harus dijalankan jika terjadi pengecualian. Berikut contohnya:

public static void main(String[] args) throws IOException {
   try {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));

       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {

       System.out.println("Error! File not found!");
   }
}
Keluaran: Kesalahan! Berkas tidak ditemukan! Kami menempatkan kode kami dalam dua blok. Di blok pertama, kami mengantisipasi bahwa kesalahan "File tidak ditemukan" mungkin terjadi. Ini trybloknya. Yang kedua, kami memberi tahu program apa yang harus dilakukan jika terjadi kesalahan. Dan jenis kesalahan spesifik: FileNotFoundException. Jika kami menempatkan kelas pengecualian yang berbeda di dalam tanda kurung blok catch, maka FileNotFoundExceptiontidak akan tertangkap.

public static void main(String[] args) throws IOException {
   try {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));
       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (ArithmeticException e) {

       System.out.println("Error! File not found!");
   }
}
Keluaran: Pengecualian di utas "utama" java.io.FileNotFoundException: C:\Users\Username\Desktop\test.txt (Sistem tidak dapat menemukan jalur yang ditentukan) Kode di catchblok tidak berjalan, karena kami "mengonfigurasi" blok ini untuk menangkap ArithmeticException, dan kode di tryblok melemparkan tipe yang berbeda: FileNotFoundException. Kami tidak menulis kode apa pun untuk ditangani FileNotFoundException, sehingga program menampilkan informasi default untuk FileNotFoundException. Di sini Anda perlu memperhatikan tiga hal. Nomor satu. Setelah pengecualian terjadi pada beberapa baris di tryblok, kode berikut tidak akan dieksekusi. Eksekusi program langsung "melompat" ke catchblok. Misalnya:

public static void main(String[] args) {
   try {
       System.out.println("Divide by zero");
       System.out.println(366/0);// This line of code will throw an exception

       System.out.println("This");
       System.out.println("code");
       System.out.println("will not");
       System.out.println("be");
       System.out.println("executed!");

   } catch (ArithmeticException e) {

       System.out.println("The program jumped to the catch block!");
       System.out.println("Error! You can't divide by zero!");
   }
}
Keluaran: Bagi dengan nol Program melompat ke blok tangkap! Kesalahan! Anda tidak dapat membagi dengan nol! Di baris kedua blok try, kami mencoba membaginya dengan 0, menghasilkan ArithmeticException. Akibatnya, baris 3-9 dari tryblok tidak akan dieksekusi. Seperti yang kami katakan, program segera mulai mengeksekusi catchblok. Nomor dua. Mungkin ada beberapa catchblok. Jika kode di tryblok mungkin melempar bukan hanya satu, tetapi beberapa jenis pengecualian, Anda dapat menulis catchblok untuk masing-masing pengecualian.

public static void main(String[] args) throws IOException {
   try {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));

       System.out.println(366/0);
       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {
      
       System.out.println("Error! File not found!");
      
   } catch (ArithmeticException e) {

       System.out.println("Error! Division by 0!");
      
   }
}
Dalam contoh ini, kami telah menulis dua catchblok. Jika a FileNotFoundExceptionterjadi di tryblok, maka blok pertama catchakan dieksekusi. Jika ArithmeticExceptionterjadi, blok kedua akan dieksekusi. Anda dapat menulis 50 catchblok jika Anda mau. Tentu saja, lebih baik tidak menulis kode yang dapat membuang 50 jenis pengecualian. :) Ketiga. Bagaimana Anda tahu pengecualian mana yang mungkin dilontarkan oleh kode Anda? Nah, Anda mungkin bisa menebak beberapa di antaranya, tetapi tidak mungkin bagi Anda untuk mengingat semuanya. Oleh karena itu, kompiler Java mengetahui pengecualian yang paling umum dan situasi di mana hal itu mungkin terjadi. Misalnya, jika Anda menulis kode yang diketahui oleh kompiler mungkin memunculkan dua jenis pengecualian, kode Anda tidak akan dikompilasi sampai Anda menanganinya. Kita akan melihat contohnya di bawah ini. Sekarang beberapa kata tentang penanganan pengecualian. Ada 2 cara untuk menangani pengecualian. Kami telah menemukan yang pertama: metode ini dapat menangani pengecualian itu sendiri dalam satu catch()blok. Ada opsi kedua: metode ini dapat mengembalikan pengecualian ke tumpukan panggilan. Maksudnya itu apa? Misalnya, kami memiliki kelas dengan printFirstString()metode yang sama, yang membaca file dan menampilkan baris pertamanya:

public static void printFirstString(String filePath) {

   BufferedReader reader = new BufferedReader(new FileReader(filePath));
   String firstString = reader.readLine();
   System.out.println(firstString);
}
Saat ini, kode kami tidak dapat dikompilasi, karena memiliki pengecualian yang tidak tertangani. Di baris 1, Anda menentukan jalur ke file. Kompiler mengetahui bahwa kode seperti itu dapat dengan mudah menghasilkan file FileNotFoundException. Pada baris 3, Anda membaca teks dari file. Proses ini dapat dengan mudah menghasilkan IOException(input/output error). Sekarang kompiler berkata kepada Anda, "Bung, saya tidak akan menyetujui kode ini dan saya tidak akan mengkompilasinya sampai Anda memberi tahu saya apa yang harus saya lakukan jika salah satu dari pengecualian ini terjadi. Dan itu pasti bisa terjadi berdasarkan kode yang Anda tulis !" Tidak ada cara untuk menyiasatinya: Anda harus menangani keduanya! Kita sudah tahu tentang metode penanganan pengecualian pertama: kita perlu memasukkan kode kita ke dalam satu tryblok dan menambahkan dua catchblok:

public static void printFirstString(String filePath) {

   try {
       BufferedReader reader = new BufferedReader(new FileReader(filePath));
       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {
       System.out.println("Error, file not found!");
       e.printStackTrace();
   } catch (IOException e) {
       System.out.println("File input/output error!");
       e.printStackTrace();
   }
}
Tapi ini bukan satu-satunya pilihan. Kita cukup membuang pengecualian lebih tinggi daripada menulis kode penanganan kesalahan di dalam metode. Ini dilakukan dengan menggunakan kata kunci throwsdalam deklarasi metode:

public static void printFirstString(String filePath) throws FileNotFoundException, IOException {
   BufferedReader reader = new BufferedReader(new FileReader(filePath));
   String firstString = reader.readLine();
   System.out.println(firstString);
}
Setelah kata kunci throws, kami menunjukkan daftar yang dipisahkan koma dari semua jenis pengecualian yang mungkin dilontarkan oleh metode tersebut. Mengapa? Sekarang, jika seseorang ingin memanggil printFirstString()metode dalam program, dia (bukan Anda) harus mengimplementasikan penanganan pengecualian. Misalnya, di tempat lain dalam program, salah satu kolega Anda menulis sebuah metode yang memanggil printFirstString()metode Anda:

public static void yourColleagueMethod() {

   // Your colleague's method does something

   //...and then calls your printFirstString() method with the file it needs
   printFirstString("C:\\Users\\Henry\\Desktop\\testFile.txt");
}
Kami mendapat kesalahan! Kode ini tidak dapat dikompilasi! Kami tidak menulis kode penanganan pengecualian dalam printFirstString()metode ini. Alhasil, tugas ini kini berada di pundak mereka yang menggunakan metode tersebut. Dengan kata lain, methodWrittenByYourColleague()metode ini sekarang memiliki 2 opsi yang sama: ia harus menggunakan try-catchblok untuk menangani kedua pengecualian, atau membuangnya kembali.

public static void yourColleagueMethod() throws FileNotFoundException, IOException {
   // The method does something

   //...and then calls your printFirstString() method with the file it needs
   printFirstString("C:\\Users\\Henry\\Desktop\\testFile.txt");
}
Dalam kasus kedua, metode berikutnya dalam tumpukan panggilan—satu pemanggilan methodWrittenByYourColleague()—harus menangani pengecualian. Itu sebabnya kami menyebutnya "melempar atau melewatkan pengecualian". Jika Anda memberikan pengecualian ke atas menggunakan kata kunci throws, kode Anda akan dikompilasi. Pada titik ini, kompiler tampaknya berkata, "Oke, oke. Kode Anda mengandung banyak kemungkinan pengecualian, tetapi saya akan mengompilasinya. Tapi kita akan kembali ke percakapan ini!" Dan ketika Anda memanggil metode apa pun yang memiliki pengecualian tidak tertangani, kompiler memenuhi janjinya dan mengingatkan Anda tentangnya lagi. Terakhir, kita akan berbicara tentang finallyblokir (maaf atas permainan kata-kata). Ini adalah bagian terakhir dari try-catch-finallytriumvirat penanganan pengecualian..

public static void main(String[] args) throws IOException {
   try {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));

       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {
       System.out.println("Error! File not found!");
       e.printStackTrace();
   } finally {
       System.out.println ("And here's the finally block!");
   }
}
Dalam contoh ini, kode di dalam finallyblok akan dieksekusi dalam kedua kasus tersebut. Jika kode di tryblok dijalankan secara penuh tanpa membuang pengecualian apa pun, finallyblok tersebut akan berjalan pada akhirnya. Jika kode di dalam tryblok diinterupsi oleh pengecualian dan program melompat ke catchblok, finallyblok akan tetap berjalan setelah kode di dalam catchblok. Mengapa ini perlu? Tujuan utamanya adalah untuk mengeksekusi kode wajib: kode yang harus dilakukan terlepas dari keadaan. Misalnya, sering membebaskan beberapa sumber daya yang digunakan oleh program. Dalam kode kami, kami membuka aliran untuk membaca informasi dari file dan meneruskannya ke objek BufferedReader. Kita harus menutup pembaca kita dan melepaskan sumber dayanya. Ini harus dilakukan apa pun yang terjadi—ketika program bekerja sebagaimana mestinya, dan ketika melontarkan pengecualian. Blok finallyadalah tempat yang sangat nyaman untuk melakukan ini:

public static void main(String[] args) throws IOException {

   BufferedReader reader = null;
   try {
       reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));

       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {
       e.printStackTrace();
   } finally {
       System.out.println ("And here's the finally block!");
       if (reader != null) {
           reader.close();
       }
   }
}
Sekarang kami yakin bahwa kami akan menjaga sumber daya, terlepas dari apa yang terjadi saat program sedang berjalan. :) Bukan hanya itu yang perlu Anda ketahui tentang pengecualian. Penanganan kesalahan adalah topik yang sangat penting dalam pemrograman. Banyak artikel yang dikhususkan untuk itu. Dalam pelajaran berikutnya, kita akan mengetahui jenis pengecualian yang ada dan cara membuat pengecualian Anda sendiri. :) Sampai jumpa!
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION