1. Jenis pengecualian

Jenis pengecualian

Semua pengecualian dibagi menjadi 4 jenis, yang sebenarnya adalah kelas yang saling mewarisi.

Throwablekelas

Kelas dasar untuk semua pengecualian adalah Throwablekelas. Kelas Throwableberisi kode yang menulis tumpukan panggilan saat ini (pelacakan tumpukan dari metode saat ini) ke sebuah array. Kami akan mempelajari apa itu pelacakan tumpukan nanti.

Operator lemparan hanya dapat menerima objek yang berasal dari Throwablekelas. Dan meskipun Anda secara teoritis dapat menulis kode seperti throw new Throwable();, biasanya tidak ada yang melakukan ini. Tujuan utama kelas Throwableadalah untuk memiliki kelas induk tunggal untuk semua pengecualian.

Errorkelas

Kelas pengecualian berikutnya adalah Errorkelas yang secara langsung mewarisi Throwablekelas tersebut. Mesin Java membuat objek kelas Error(dan keturunannya) ketika masalah serius terjadi . Misalnya, kerusakan perangkat keras, memori tidak mencukupi, dll.

Biasanya, sebagai programmer, tidak ada yang dapat Anda lakukan dalam situasi di mana kesalahan seperti itu (jenis yang Errorharus dibuang) telah terjadi dalam program: kesalahan ini terlalu serius. Yang dapat Anda lakukan hanyalah memberi tahu pengguna bahwa program mogok dan/atau menulis semua informasi yang diketahui tentang kesalahan ke log program.

Exceptionkelas

Kelas Exceptionand RuntimeExceptionadalah untuk kesalahan umum yang terjadi dalam pengoperasian banyak metode. Tujuan dari setiap pengecualian yang dilemparkan adalah untuk ditangkap oleh catchblok yang tahu cara menanganinya dengan benar.

Ketika suatu metode tidak dapat menyelesaikan pekerjaannya karena alasan tertentu, ia harus segera memberi tahu metode pemanggil dengan melemparkan pengecualian dari jenis yang sesuai.

Dengan kata lain, jika sebuah variabel sama dengan null, metode akan melempar NullPointerException. Jika argumen yang salah diteruskan ke metode, itu akan membuang InvalidArgumentException. Jika metode ini secara tidak sengaja membagi dengan nol, itu akan membuang ArithmeticException.

RuntimeExceptionkelas

RuntimeExceptionsadalah subset dari Exceptions. Kami bahkan dapat mengatakan bahwa RuntimeExceptionini adalah versi ringan dari pengecualian biasa ( Exception) — lebih sedikit persyaratan dan batasan yang dikenakan pada pengecualian tersebut

Anda akan mempelajari perbedaan antara Exceptiondan RuntimeExceptionnanti.


2. Throws: memeriksa pengecualian

Melempar: pengecualian diperiksa

Semua pengecualian Java terbagi dalam 2 kategori: dicentang dan tidak dicentang .

Semua pengecualian yang mewarisi RuntimeExceptionatau Errordianggap sebagai pengecualian yang tidak dicentang . Semua lainnya diperiksa pengecualian .

Penting!

Dua puluh tahun setelah pengecualian diperiksa diperkenalkan, hampir setiap programmer Java menganggap ini sebagai bug. Dalam kerangka modern populer, 95% dari semua pengecualian tidak dicentang. Bahasa C#, yang hampir menyalin Java persis, tidak menambahkan pengecualian yang dicentang .

Apa perbedaan utama antara pengecualian yang dicentang dan tidak dicentang ?

Ada persyaratan tambahan yang dikenakan pada pengecualian yang diperiksa . Secara kasar, mereka adalah ini:

Persyaratan 1

Jika sebuah metode melontarkan pengecualian yang dicentang , ia harus menunjukkan jenis pengecualian dalam tanda tangannya . Dengan begitu, setiap metode yang memanggilnya menyadari bahwa "pengecualian yang berarti" ini mungkin terjadi di dalamnya.

Tunjukkan pengecualian yang dicentang setelah parameter metode setelah throwskata kunci (jangan gunakan throwkata kunci secara tidak sengaja). Ini terlihat seperti ini:

type method (parameters) throws exception

Contoh:

pengecualian diperiksa pengecualian yang tidak dicentang
public void calculate(int n) throws Exception
{
   if (n == 0)
      throw new Exception("n is null!");
}
public void calculate(n)
{
   if (n == 0)
      throw new RuntimeException("n is null!");
}

Pada contoh di sebelah kanan, kode kita melontarkan pengecualian yang tidak dicentang — tidak diperlukan tindakan tambahan. Pada contoh di sebelah kiri, metode melontarkan pengecualian yang dicentang , sehingga throwskata kunci ditambahkan ke tanda tangan metode bersama dengan jenis pengecualian.

Jika suatu metode mengharapkan untuk membuang beberapa pengecualian yang diperiksa , semuanya harus ditentukan setelah throwskata kunci, dipisahkan dengan koma. Urutannya tidak penting. Contoh:

public void calculate(int n) throws Exception, IOException
{
   if (n == 0)
      throw new Exception("n is null!");
   if (n == 1)
      throw new IOException("n is 1");
}

Persyaratan 2

Jika Anda memanggil metode yang telah memeriksa pengecualian pada tanda tangannya, Anda tidak dapat mengabaikan fakta bahwa metode tersebut melemparkannya.

Anda harus menangkap semua pengecualian tersebut dengan menambahkan catchblok untuk masing-masing, atau dengan menambahkannya ke throwsklausa untuk metode Anda.

Seolah-olah kita mengatakan, " Pengecualian ini sangat penting sehingga kita harus menangkapnya. Dan jika kita tidak tahu cara menanganinya, maka siapa pun yang mungkin memanggil metode kita harus diberi tahu bahwa pengecualian semacam itu dapat terjadi di dalamnya.

Contoh:

Bayangkan kita sedang menulis metode untuk menciptakan dunia yang dihuni oleh manusia. Jumlah awal orang dilewatkan sebagai argumen. Jadi kita perlu menambahkan pengecualian jika jumlah orang terlalu sedikit.

Menciptakan Bumi Catatan
public void createWorld(int n) throws EmptyWorldException, LonelyWorldException
{
   if (n == 0)
      throw new EmptyWorldException("There are no people!");
   if (n == 1)
      throw new LonelyWorldException ("There aren't enough people!");
   System.out.println("A wonderful world was created. Population: " + n);
}
Metode ini berpotensi melontarkan dua pengecualian yang diperiksa :

  • Pengecualian Dunia Kosong
  • Pengecualian Dunia Kesepian

Panggilan metode ini dapat ditangani dengan 3 cara:

1. Jangan tangkap pengecualian apa pun

Ini paling sering dilakukan ketika metode tidak mengetahui cara menangani situasi dengan benar.

Kode Catatan
public void createPopulatedWorld(int population)
throws EmptyWorldException, LonelyWorldException
{
   createWorld(population);
}
Metode pemanggilan tidak menangkap pengecualian dan harus memberi tahu orang lain tentangnya: ia menambahkannya ke klausanya throwssendiri

2. Tangkap beberapa pengecualian

Kami menangani kesalahan yang dapat kami tangani. Tapi yang tidak kami mengerti, kami melemparkannya ke metode pemanggilan. Untuk melakukan ini, kita perlu menambahkan nama mereka ke klausa throws:

Kode Catatan
public void createNonEmptyWorld(int population)
throws EmptyWorldException
{
   try
   {
      createWorld(population);
   }
   catch (LonelyWorldException e)
   {
      e.printStackTrace();
   }
}
Penelepon menangkap hanya satu pengecualian yang dicentangLonelyWorldException — . Pengecualian lain harus ditambahkan ke tanda tangannya, yang menunjukkannya setelah throwskata kunci

3. Tangkap semua pengecualian

Jika metode tidak membuang pengecualian ke metode pemanggilan, maka metode pemanggilan selalu yakin bahwa semuanya bekerja dengan baik. Dan itu tidak akan dapat mengambil tindakan apa pun untuk memperbaiki situasi luar biasa.

Kode Catatan
public void createAnyWorld(int population)
{
   try
   {
      createWorld(population);
   }
   catch (LonelyWorldException e)
   {
      e.printStackTrace();
   }
   catch (EmptyWorldException e)
   {
      e.printStackTrace();
   }
}
Semua pengecualian ditangkap dalam metode ini. Penelepon akan yakin bahwa semuanya berjalan dengan baik.


3. Membungkus pengecualian

Pengecualian yang diperiksa tampak keren dalam teori, tetapi ternyata menjadi frustrasi besar dalam praktiknya.

Misalkan Anda memiliki metode yang sangat populer di proyek Anda. Itu dipanggil dari ratusan tempat di program Anda. Dan Anda memutuskan untuk menambahkan pengecualian baru yang diperiksa untuk itu. Dan mungkin pengecualian yang diperiksa ini sangat penting dan sangat istimewa sehingga hanya main()metode yang tahu apa yang harus dilakukan jika tertangkap.

Itu berarti Anda harus menambahkan pengecualian yang dicentang ke throwsklausa dari setiap metode yang memanggil metode super populer Anda . Serta di throwsklausa semua metode yang memanggil metode tersebut. Dan metode yang memanggil metode tersebut.

Akibatnya, throwsklausa setengah dari metode dalam proyek mendapatkan pengecualian baru yang diperiksa . Dan tentu saja proyek Anda dicakup oleh pengujian, dan sekarang pengujian tidak dapat dikompilasi. Dan sekarang Anda juga harus mengedit klausa lemparan dalam pengujian Anda.

Dan kemudian semua kode Anda (semua perubahan dalam ratusan file) harus ditinjau oleh pemrogram lain. Dan pada titik ini kami bertanya pada diri sendiri mengapa kami membuat begitu banyak perubahan berdarah pada proyek ini? Hari(s?) kerja, dan tes rusak - semua demi menambahkan satu pengecualian diperiksa ?

Dan tentu saja, masih ada masalah terkait pewarisan dan penggantian metode. Masalah yang muncul dari pengecualian yang diperiksa jauh lebih besar daripada manfaatnya. Intinya adalah sekarang hanya sedikit orang yang menyukainya dan sedikit orang yang menggunakannya.

Namun masih banyak kode (termasuk kode perpustakaan Java standar) yang berisi pengecualian yang dicentang ini . Apa yang harus dilakukan dengan mereka? Kita tidak bisa mengabaikannya, dan kita tidak tahu bagaimana menanganinya.

Pemrogram Java mengusulkan untuk membungkus pengecualian yang diperiksa dalam RuntimeException. Dengan kata lain, tangkap semua pengecualian yang dicentang lalu buat pengecualian yang tidak dicentang (misalnya, RuntimeException) dan buang saja. Melakukannya terlihat seperti ini:

try
{
   // Code where a checked exception might occur
}
catch(Exception exp)
{
   throw new RuntimeException(exp);
}

Ini bukan solusi yang sangat bagus, tetapi tidak ada kriminal di sini: pengecualian hanya dimasukkan ke dalam file RuntimeException.

Jika diinginkan, Anda dapat dengan mudah mengambilnya dari sana. Contoh:

Kode Catatan
try
{
   // Code where we wrap the checked exception
   // in a RuntimeException
}
catch(RuntimeException e)
{
   Throwable cause = e.getCause();
   if (cause instanceof Exception)
   {
      Exception exp = (Exception) cause;
      // Exception handling code goes here
   }
}







Dapatkan pengecualian yang disimpan di dalam RuntimeExceptionobjek. Variabel causemungkin null

Menentukan jenisnya dan mengubahnya menjadi jenis pengecualian yang diperiksa .


4. Menangkap banyak pengecualian

Pemrogram sangat benci untuk menggandakan kode. Mereka bahkan menemukan prinsip pengembangan yang sesuai: Don't Repeat Yourself (DRY) . Namun saat menangani pengecualian, sering kali sebuah tryblok diikuti oleh beberapa catchblok dengan kode yang sama.

Atau mungkin ada 3 catchblok dengan kode yang sama dan 2 catchblok lainnya dengan kode identik lainnya. Ini adalah situasi standar ketika proyek Anda menangani pengecualian secara bertanggung jawab.

Dimulai dengan versi 7, bahasa Java menambahkan kemampuan untuk menentukan beberapa jenis pengecualian dalam satu catchblok. Ini terlihat seperti ini:

try
{
   // Code where an exception might occur
}
catch (ExceptionType1 | ExceptionType2 | ExceptionType3 name)
{
   // Exception handling code
}

Anda dapat memiliki blok sebanyak catchyang Anda inginkan. Namun, satu catchblok tidak dapat menentukan pengecualian yang mewarisi satu sama lain. Dengan kata lain, Anda tidak dapat menulis catch ( Exception| RuntimeExceptione), karena RuntimeExceptionclass mewarisi Exception.



5. Pengecualian khusus

Anda selalu dapat membuat kelas pengecualian Anda sendiri. Anda cukup membuat kelas yang mewarisi RuntimeExceptionkelas tersebut. Ini akan terlihat seperti ini:

class ClassName extends RuntimeException
{
}

Kami akan membahas detailnya saat Anda mempelajari OOP, pewarisan, konstruktor, dan penggantian metode.

Namun, bahkan jika Anda hanya memiliki kelas sederhana seperti ini (sepenuhnya tanpa kode), Anda masih dapat membuang pengecualian berdasarkan itu:

Kode Catatan
class Solution
{
   public static void main(String[] args)
   {
      throw new MyException();
   }
}

class MyException extends RuntimeException
{
}




Lemparkan yang tidak dicentang MyException .

Dalam pencarian Java Multithreading , kami akan menyelami lebih dalam untuk bekerja dengan pengecualian khusus kami sendiri.