1. Jenis pengecualian

Semua pengecualian dibahagikan kepada 4 jenis, yang sebenarnya merupakan kelas yang mewarisi satu sama lain.

Throwablekelas

Kelas asas untuk semua pengecualian ialah Throwablekelas. Kelas Throwablemengandungi kod yang menulis timbunan panggilan semasa (jejak tindanan kaedah semasa) kepada tatasusunan. Kita akan belajar apa itu surih tindanan sedikit kemudian.

Operator lontaran hanya boleh menerima objek yang berasal dari Throwablekelas. Dan walaupun anda secara teorinya boleh menulis kod seperti throw new Throwable();, tiada siapa yang biasanya melakukan ini. Tujuan utama kelas Throwableadalah untuk mempunyai kelas induk tunggal untuk semua pengecualian.

Errorkelas

Kelas pengecualian seterusnya ialah Errorkelas, yang mewarisi Throwablekelas secara langsung. Mesin Java mencipta objek kelas Error(dan keturunannya) apabila masalah serius telah berlaku . Contohnya, kerosakan perkakasan, memori tidak mencukupi, dsb.

Biasanya, sebagai pengaturcara, tiada apa yang boleh anda lakukan dalam situasi di mana ralat sedemikian (jenis yang patut Errordilemparkan) telah berlaku dalam atur cara: ralat ini terlalu serius. Apa yang anda boleh lakukan ialah memberitahu pengguna bahawa program itu ranap dan/atau menulis semua maklumat yang diketahui tentang ralat pada log program.

Exceptionkelas

Kelas Exceptiondan RuntimeExceptionadalah untuk ralat biasa yang berlaku dalam pengendalian banyak kaedah. Matlamat setiap pengecualian yang dilemparkan adalah untuk ditangkap oleh catchblok yang tahu cara mengendalikannya dengan betul.

Apabila kaedah tidak dapat menyelesaikan kerjanya atas sebab tertentu, ia harus segera memberitahu kaedah panggilan dengan membuang pengecualian jenis yang sesuai.

Dalam erti kata lain, jika pembolehubah adalah sama dengan null, kaedah akan membuang NullPointerException. Jika hujah yang salah dihantar kepada kaedah, ia akan membuang InvalidArgumentException. Jika kaedah secara tidak sengaja membahagi dengan sifar, ia akan membuang ArithmeticException.

RuntimeExceptionkelas

RuntimeExceptionsialah subset daripada Exceptions. Kita juga boleh mengatakan bahawa RuntimeExceptionia adalah versi ringan bagi pengecualian biasa ( Exception) — lebih sedikit keperluan dan sekatan dikenakan ke atas pengecualian tersebut

Anda akan mengetahui perbezaan antara Exceptiondan RuntimeExceptionkemudian.


2. Throws: pengecualian diperiksa

Semua pengecualian Java jatuh ke dalam 2 kategori: ditandai dan dinyahtanda .

Semua pengecualian yang mewarisi RuntimeExceptionatau Errordianggap pengecualian tidak ditanda . Semua yang lain disemak pengecualian .

Penting!

Dua puluh tahun selepas pengecualian yang diperiksa diperkenalkan, hampir setiap pengaturcara Java menganggap ini sebagai pepijat. Dalam rangka kerja moden yang popular, 95% daripada semua pengecualian tidak ditandai. Bahasa C#, yang hampir menyalin Java dengan tepat, tidak menambah pengecualian yang diperiksa .

Apakah perbezaan utama antara pengecualian yang disemak dan tidak disemak ?

Terdapat keperluan tambahan yang dikenakan ke atas pengecualian yang disemak . Secara kasarnya, mereka adalah ini:

Keperluan 1

Jika kaedah melemparkan pengecualian yang ditandai , ia mesti menunjukkan jenis pengecualian dalam tandatangannya . Dengan cara itu, setiap kaedah yang memanggilnya menyedari bahawa "pengecualian yang bermakna" ini mungkin berlaku di dalamnya.

Nyatakan pengecualian yang disemak selepas parameter kaedah selepas throwskata kunci (jangan gunakan throwkata kunci secara tidak sengaja). Ia kelihatan seperti ini:

type method (parameters) throws exception

Contoh:

pengecualian diperiksa pengecualian tidak ditanda
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!");
}

Dalam contoh di sebelah kanan, kod kami membuang pengecualian yang tidak ditanda — tiada tindakan tambahan diperlukan. Dalam contoh di sebelah kiri, kaedah membuang pengecualian yang ditandai , jadi throwskata kunci ditambahkan pada tandatangan kaedah bersama-sama dengan jenis pengecualian.

Jika kaedah menjangkakan untuk membuang berbilang pengecualian yang ditandakan , kesemuanya mesti dinyatakan selepas throwskata kunci, dipisahkan dengan koma. Perintah itu 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");
}

Keperluan 2

Jika anda memanggil kaedah yang telah menyemak pengecualian dalam tandatangannya, anda tidak boleh mengabaikan fakta bahawa kaedah itu membuangnya.

Anda mesti sama ada menangkap semua pengecualian tersebut dengan menambahkan catchblok untuk setiap satu, atau dengan menambahkannya pada throwsklausa untuk kaedah anda.

Seolah-olah kita berkata, " Pengecualian ini sangat penting sehingga kita mesti menangkapnya. Dan jika kita tidak tahu cara mengendalikannya, maka sesiapa yang mungkin memanggil kaedah kita mesti dimaklumkan bahawa pengecualian tersebut boleh berlaku di dalamnya.

Contoh:

Bayangkan bahawa kita sedang menulis kaedah untuk mencipta dunia yang dihuni oleh manusia. Bilangan awal orang diluluskan sebagai hujah. Jadi kita perlu menambah pengecualian jika terdapat terlalu sedikit orang.

Mencipta 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);
}
Kaedah ini berpotensi membuang dua pengecualian yang diperiksa :

  • EmptyWorldException
  • LonelyWorldException

Panggilan kaedah ini boleh dikendalikan dalam 3 cara:

1. Jangan tangkap sebarang pengecualian

Ini paling kerap dilakukan apabila kaedah itu tidak tahu cara mengendalikan keadaan dengan betul.

Kod Catatan
public void createPopulatedWorld(int population)
throws EmptyWorldException, LonelyWorldException
{
   createWorld(population);
}
Kaedah panggilan tidak menangkap pengecualian dan mesti memberitahu orang lain tentangnya: ia menambahkannya pada klausanya throwssendiri

2. Tangkap beberapa pengecualian

Kami menangani kesilapan yang boleh kami tangani. Tetapi yang kita tidak faham, kita buang ke kaedah panggilan. Untuk melakukan ini, kita perlu menambah nama mereka pada klausa lontaran:

Kod Catatan
public void createNonEmptyWorld(int population)
throws EmptyWorldException
{
   try
   {
      createWorld(population);
   }
   catch (LonelyWorldException e)
   {
      e.printStackTrace();
   }
}
Pemanggil hanya menangkap satu pengecualian yang diperiksaLonelyWorldException — . Pengecualian lain mesti ditambahkan pada tandatangannya, menunjukkannya selepas throwskata kunci

3. Tangkap semua pengecualian

Jika kaedah tidak membuang pengecualian kepada kaedah panggilan, maka kaedah panggilan sentiasa yakin bahawa semuanya berfungsi dengan baik. Dan ia tidak akan dapat mengambil sebarang tindakan untuk membetulkan situasi yang luar biasa.

Kod Catatan
public void createAnyWorld(int population)
{
   try
   {
      createWorld(population);
   }
   catch (LonelyWorldException e)
   {
      e.printStackTrace();
   }
   catch (EmptyWorldException e)
   {
      e.printStackTrace();
   }
}
Semua pengecualian terperangkap dalam kaedah ini. Pemanggil akan yakin bahawa semuanya berjalan lancar.


3. Menangkap pelbagai pengecualian

Pengaturcara sangat tidak suka menduplikasi kod. Mereka juga menghasilkan prinsip pembangunan yang sepadan — KERING : Jangan Ulangi Sendiri. Tetapi apabila mengendalikan pengecualian, terdapat keadaan yang kerap apabila tryblok diikuti oleh beberapa catchblok dengan kod yang sama.

Atau mungkin terdapat 3 catchblok dengan kod yang sama dan 2 catchblok lagi dengan kod yang serupa. Ini adalah situasi standard apabila projek anda mengendalikan pengecualian secara bertanggungjawab.

Bermula dengan versi 7, dalam bahasa Java menambahkan keupayaan untuk menentukan pelbagai jenis pengecualian dalam satu catchblok. Ia kelihatan lebih kurang seperti ini:

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

Anda boleh mempunyai seberapa banyak catchblok yang anda mahu. Walau bagaimanapun, satu catchblok tidak boleh menentukan pengecualian yang mewarisi satu sama lain. Dengan kata lain, anda tidak boleh menulis catch ( Exception| RuntimeExceptione), kerana RuntimeExceptionkelas mewarisi Exception.