CodeGym /Kurslar /Java SELF AZ /Java-dakı istisnaların növləri

Java-dakı istisnaların növləri

Java SELF AZ
Səviyyə , Dərs
Mövcuddur

1. İstisnalar növləri

Java-da istisnalar növləri

Bütün istisnalar əslində bir-birindən miras alınmış siniflər olan 4 növə bölünür.

Throwable sinifi

Bütün istisnalar üçün ən əsas sinif Throwable sinifidir. Throwable sinifində funksiyaların çağırışlarını cari stack-trace kimi bir massiva yazan kod yerləşir. Stack-trace nədir, bunu bir az sonra öyrənəcəyik.

throw operatoruna yalnız Throwable sinifindən miras alınmış sinifin obyektini ötürmək olar. Həmçinin, nəzəri olaraq throw new Throwable(); tipli kod yazmaq mümkündür — amma adətən heç kim belə etməz. Throwable sinifinin əsas məqsədi bütün istisnalar üçün birləşmiş sinif-prototip olmaqdır.

Error sinifi

Növbəti istisna sinifi Error sinifidir — bu da Throwable sinifindən birbaşa miras alır. Error (və onun miras alan siniflərinin) tipində obyektləri Java maşını ciddi problemlər zamanı yaradır. Məsələn, yaddaş çatışmazlığı, proqramın nasazlığı və s.

Adətən siz proqramçı kimi Error tipli bir səhv baş verdikdə heç nə edə bilməzsiniz: belə bir səhv çox ciddidir. Siz edə biləcəyiniz yeganə şey istifadəçiyə proqramın qəza ilə dayandığını bildirmək və ya səhv haqqında bütün məlum məlumatları proqramın logunda yazmaqdır.

Exception sinifi

Exception (və RuntimeException) tipli istisnalar — bir çox metodların işi zamanı ortaya çıxan adi səhvlərdir. Hər bir atılan istisnanın məqsədi onu bilən catch bloku tərəfindən tutulmaqdır.

Hər hansı bir metod hansısa səbəbdən işini yerinə yetirə bilməyəcəksə, dərhal uyğun tipdə bir istisna ataraq çağıran metoda bu barədə məlumat verməlidir.

Başqa sözlə, əgər hansısa dəyişən null olarsa, metod NullPointerException atacaq, əgər metoda yalnış arqumentlər ötürülsə — InvalidArgumentException atacaq, əgər metodda təsadüfən sıfıra bölmə olarsa — ArithmeticException.

RuntimeException sinifi

RuntimeExceptionException istisnalarının bir növüdür. Hətta deyə bilərik ki, RuntimeException — adi istisnaların (Exception) sadələşdirilmiş bir versiyasıdır: belə istisnalara daha az tələb və məhdudiyyətlər tətbiq edilir

ExceptionRuntimeException arasındakı fərqi daha sonra öyrənəcəksiniz


2. Yoxlanılan istisnalar: throws, checked exceptions

Yoxlanılan istisnalar: throws, checked exceptions

Javadakı istisnalar iki kateqoriyaya bölünür — yoxlanılan (checked) və yoxlanılmayan (unchecked).

Bütün RuntimeExceptionError siniflərindən miras qalmış istisnalar unchecked-istisnalar sayılır, qalanları isə — checked-istisnalar.

Vacibdir!

Yoxlanılan istisnaların tətbiqindən 20 il keçdikdən sonra, demək olar ki, bütün Java proqramçıları bunun bir səhv olduğunu düşünürlər. Müasir məşhur framework-lərdəki bütün istisnaların 95%-i yoxlanılmayan istisnalardır. C# kimi dil, Java-nı demək olar ki, tamamilə kopyalamağı qərara aldı, lakin yenə də checked-istisnalar əlavə etmədi.

Bəs checked-istisnalar ilə unchecked arasında əsas fərq nədir?

Checked-istisnalara əlavə tələblər tətbiq olunur. Bu tələblər təxminən belədir:

Tələb 1

Əgər metod checked-istisna atırsa, bu istisnanın növü metodun başlığında qeyd olunmalıdır (metodun imzası). Beləliklə, həmin metodu çağıran bütün digər metodlar həmin metodun vacib bir istisna ata biləcəyini bilirlər.

Checked-istisnaların göstərilməsi metodun parametrlərindən sonra throws açar sözündən sonra olur (bu throw ilə qarışdırılmamalıdır). Bu təxminən belə görünür:

növ metod (parametrlər) throws istisna

Nümunə:

checked-istisna unchecked-istisna
public void calculate(int n) throws Exception
{
   if (n == 0)
      throw new Exception("n sıfıra bərabərdir!");
}
public void calculate(n)
{
   if (n == 0)
      throw new RuntimeException("n sıfıra bərabərdir!");
}

Sağdakı nümunədə kodumuz unchecked-istisna atır — heç bir əlavə əməliyyat tələb olunmur. Soldakı nümunədə metod checked-istisna atır, buna görə metodun imzasına throws açar sözü əlavə edilib və istisna tipi göstərilib.

Əgər metod bir neçə checked-istisna atmağı planlaşdırırsa, onların hamısını throws açar sözündən sonra vergüllə yazmaq lazımdır. Sıra vacib deyil. Nümunə:

public void calculate(int n) throws Exception, IOException
{
   if (n == 0)
      throw new Exception("n sıfıra bərabərdir!");
   if (n == 1)
      throw new IOException("n birə bərabərdir");
}

Tələb 2

Əgər imzasında checked-istisnalar olan bir metodu çağırırsınızsa, bu faktı ignor edə bilməzsiniz.

Bütün bu istisnaları catch blokları əlavə edərək tutmalı, ya da onları metodunuzun throwsunda qeyd etməlisiniz.

Sanki özümüzə deyirik: bu istisnalar çox vacibdir, ona görə də onları mütləq tutmalıyıq. Əgər onları necə tutacağımızı bilməsək, metodumuzu çağıranlara xəbər verməliyik ki, belə istisnalar yarana bilər.

Nümunə:

Təsəvvür edin ki, insanlarla dolacaq bir dünya yaratmalı olan bir metod yazırıq. İnsanların başlanğıc sayı parametr kimi ötürülür. İnsanların sayı çox azdırsa, istisnaları əlavə etməliyik.

Dünyanı yaratmaq Qeyd
public void dunyaYarat(int n) throws BosDunya,TenhaDunya
{
   if (n == 0)
      throw new BosDunya("İnsanlar ümumiyyətlə yoxdur!");
   if (n == 1)
      throw new TenhaDunya("İnsanlar çox azdır!");
   System.out.println("Möhtəşəm bir dünya yaradıldı. Əhali: " + n);
}
Metod potensial olaraq iki checked-istisna ata bilər:

  • BosDunya
  • TenhaDunya

Bu metodu çağırmağın 3 yolu var:

1. Yaradan istisnaları tutmuruq

Adətən belə olur ki, metoddakı vəziyyəti düzgün emal etmək məlum olmur.

Kod Qeyd
public void doluluDunyaYarat(int population)
throws BosDunya, TenhaDunya
{
   dunyaYarat(population);
}
Çağırıcı metod istisnaları tutmur və onların başqa metodlarla paylaşılması lazım olur: onları throwsa əlavə edir

2. Bəzi istisnaları tutmaq

Aydın səhvləri emal edirik, anlaşılmayanları - çağırıcı metoda göndəririk. Bunun üçün onların adlarını throws-ə əlavə etmək lazımdır:

Kod Qeyd
public void bosOlmayanDunyaYarat(int population)
throws BosDunya
{
   try
   {
      dunyaYarat(population);
   }
   catch (TenhaDunya e)
   {
      e.printStackTrace();
   }
}
Çağırıcı metod yalnız bir checked-istisnaTenhaDunya-ı tutur, digəri isə metodun imzasında əlavə olunmalıdır: throws-dan sonra

3. Bütün istisnaları tuturuq

Əgər metod, çağırıcı metoda heç bir istisna geri qaytarmazsa, çağırıcı metod hər şeyin uğurla həyata keçdiyinə əmin olacaq. Ancaq vəziyyətin düzəldilməsi üçün uğursuz bir addım ata bilməyəcək.

Kod Qeyd
public void herHansiBirDunyaYarat(int population)
{
   try
   {
      dunyaYarat(population);
   }
   catch(TenhaDunya e)
   {
      e.printStackTrace();
   }
   catch(BosDunya e)
   {
      e.printStackTrace();
   }
}
Bu metodda bütün səhvlər tutulur. Çağırıcı metod hər şeyin uğurla həyata keçirildiyinə əmin olacaq.


3. İstisnaların örtülməsi

Checked-istisnalar nəzəriyyə baxımından çox gözəl bir şey kimi görünürdü, amma praktikada tam bir xəyal qırıqlığı oldu.

Tutaq ki, sizin layihənizdə proqramın yüzlərlə yerindən çağırılan çox məşhur bir metodunuz var. Və siz bu metoda yeni bir checked-istisna əlavə etmək qərarına gəldiniz. Və çox yaxşı ola bilər ki, bu checked-istisna həqiqətən çox əhəmiyyətli və xüsusi olsun ki, yalnız main() metodu bu istisnanı tutduğu zaman nə edəcəyini bilir.

Buna görə də sizə checked-istisna əlavə etmək lazım gələcək throws-a bütün metodlara, hansı ki sizin məşhur metodunuzu çağırır. Həmçinin, həmin metodları çağıran metodlara da əlavə etmək lazım gələcək. Həmçinin, həmin metodları çağıran metodlara da.

Nəticədə sizin layihədəki metodların yarısında throws-da yeni bir checked-istisna əlavə olunacaq. Daha sonra məlum olacaq ki, sizin layihəniz testlər ilə əhatə olunmuşdur və bu testlər artıq kompilyasiya olunmur. Sizə həmçinin testlərdəki throws-ı da düzəltmək lazım gələcək.

Sonra isə bütün kodunuzu (yüzlərlə fayla düzəlişlər) digər proqramçılar nəzərdən keçirməli olacaqlar. Və burada özünüzə bir sual veririk: bəs layihəyə bu qədər dəyişikliyi hansı məqsədlə etdik? Bir-iki gün iş, sındırılmış testlər, və bütün bunlar bir checked-istisna əlavə etmək üçün?

Nəzərə alın ki, metodların miras alınması və təkrar müəyyənləşdirilməsi ilə bağlı da problemlər mövcuddur. Checked-istisnaların gətirdiyi problemlər onların faydasından çoxdur. Ümumiyyətlə, bu günlərdə çox az adam onları sevir və istifadə edir.

Amma yenə də çoxlu kod (o cümlədən Java standart kitabxanalarının kodu) bu checked-istisnaları ehtiva edir. Bəs bunlarla nə etmək lazımdır? Onları görməzdən gəlinə bilməz, onları necə idarə edəcəyimiz isə məlum deyil.

Java proqramçıları checked-istisnaları RuntimeException-ın içinə «sarmağı» təklif etdilər. Başqa sözlə, bütün checked-istisnaları tutaraq, onların əvəzinə unchecked-istisnalar (məsələn, RuntimeException) yaradıb və məhz onları atmaq. Bu, təxminən belə görünür:

try
{
   burada checked-istisna meydana gələ bilər
}
catch(Exception exp)
{
   throw new RuntimeException(exp);
}

Bu çox da gözəl bir həll deyil, amma heç də qəbuledilməz deyil: istisna sadəcə RuntimeException-ın içinə qoyulub.

İstənilən zaman onu buradan asanlıqla çıxarmaq olar. Nümunə:

Kod Qeyd
try
{
   // burada checked istisnanı RuntimeException-a yerləşdirmişik
}
catch(RuntimeException e)
{
   Throwable cause = e.getCause();
   if (cause instanceof Exception)
   {
      Exception exp = (Exception) cause;
      // burada Exception-un idarə olunması üçün kod
   }
}







İstisnanı RuntimeException obyektinin içində alırıq. cause null ola bilər.

Onun tipini müəyyənləşdiririk və onu checked tipli dəyişənə çevririk.


4. Çoxlu istisna tutma

Proqramçılar kodun təkrarlanmasını çox sevmirlər. Bunun üçün hətta bir inkişaf prinsipi də yaradıblar — DRY: Don’t Repeat Yourself. Amma istisnaları emal edərkən tez-tez belə hallar olur ki, try blokundan sonra eyni kodlu bir neçə catch bloku gəlir.

Və ya məsələn, bir layihədə 3 catch bloku bir cür kodda olur və başqa 2 catch bloku başqa cür kodla. Bu, ümumi praktik vəziyyətdir, əgər sizin layihədə istisnaların emalına ciddi yanaşılırsa.

Java dilində 7-ci versiyadan başlayaraq bir catch blokunda bir neçə istisna tipini göstərmək imkanı əlavə edilmişdir. Bu belə görünür:

try
{
   səhvin baş verə biləcəyi kod
}
catch(Tipİstisna1 | Tipİstisna2 | Tipİstisna3 ad)
{
   istisnaların emal kodu
}

catch bloklarının sayı istənilən qədər ola bilər. Amma bir catch blokunda bir-biri ilə miras əlaqəsi olan istisnaları göstərmək olmaz. Yəni, belə bir şey yazmaq olmaz: catch (Exception | RuntimeException e), çünki RuntimeException sinifi Exception-dan miras alır.



5. Öz istisnalarınız

Həmişə öz xüsusi istisna sinifinizi yarada bilərsiniz. Məsələn, RuntimeException sinifindən irs alaraq. Bu təxminən belə görünəcək:

class SinifAdi extends RuntimeException
{
}

Detalları OOP, irsiyyət, konstruktorlar və metodların yenidən yazılmasını öyrəndiyiniz zaman müzakirə edəcəyik.

Ancaq, hətta belə sadə bir sinifiniz olsa belə – ümumiyyətlə kodsuz, yenə də onun istisnalarını ata bilərsiniz:

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

class MyException extends RuntimeException
{
}




Unchecked istisna MyException atılır.

Öz istisnalarınızla detallı işi Java Multithreading kvestində nəzərdən keçirəcəyik.

Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION