Məzmuna keç
Educora
İrəli17 dəq10 / 18

İstisnalar: xətaların idarə olunması

try/catch/finally ilə xətaları tut, yoxlanılan və yoxlanılmayan istisnaları fərqləndir, throw ilə istisna at və öz istisna sinfini yarat.

Özünü yoxla
Bu dərsdə öyrənəcəksən
  • İstisnanın nə olduğunu izah etmək və stek izini oxumaq
  • try, catch və finally bloklarından istifadə etmək
  • Yoxlanılan və yoxlanılmayan istisnaları fərqləndirmək və öz istisna sinfini yazmaq

İstifadəçi yaş yerinə «abc» yazdı, fayl silinib, internet kəsildi — real proqramlarda hər şey plan üzrə getmir. Yaxşı proqram belə hallarda «çökmür», problemi nəzakətlə bildirir və işini davam etdirir. Java-da gözlənilməz vəziyyətləri istisnalar (exceptions) vasitəsilə idarə edirlər.

İstisna nədir?

İstisna proqramın normal axınını pozan hadisəni təsvir edən obyektdir. İstisna baş verəndə Java onu «atır» (throw): cari metod dərhal dayanır və istisna onu tutacaq kod tapılana qədər çağırışlar zənciri ilə yuxarı qalxır. Heç kim tutmasa, proqram dayanır və konsola stek izi (stack trace) çıxır.

Java
public class Main {
    public static void main(String[] args) {
        int[] marks = {5, 4, 3};
        System.out.println("Start");
        System.out.println(marks[5]);
        System.out.println("End");
    }
}
Gözlənilən nəticə
Start
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 3
	at Main.main(Main.java:5)

Stek izini aşağıdan yuxarı deyil, yuxarıdan aşağı oxu: əvvəlcə istisnanın tipi (ArrayIndexOutOfBoundsException), sonra mesajı (5-ci indeks 3 uzunluqlu massivdən kənardadır), sonra isə harada baş verdiyi — Main.java faylının 5-ci sətri. «End» çap olunmadı: istisnadan sonra metodun qalan hissəsi icra olunmur.

try, catch və finally

Təhlükəli kodu try blokuna yerləşdiririk. İstisna baş verərsə, idarəetmə uyğun tipli catch blokuna keçir. finally bloku isə hər halda — istisna olsa da, olmasa da — icra olunur; orada adətən faylı və ya bağlantını bağlamaq kimi «yığışdırma» işləri görülür.

Java
public class Main {
    public static void main(String[] args) {
        String[] inputs = {"42", "abc", "0"};
        for (String input : inputs) {
            try {
                int n = Integer.parseInt(input);
                System.out.println("100 / " + n + " = " + (100 / n));
            } catch (NumberFormatException e) {
                System.out.println("Not a number: " + e.getMessage());
            } catch (ArithmeticException e) {
                System.out.println("Math error: " + e.getMessage());
            } finally {
                System.out.println("-- checked \"" + input + "\"");
            }
        }
    }
}
Gözlənilən nəticə
100 / 42 = 2
-- checked "42"
Not a number: For input string: "abc"
-- checked "abc"
Math error: / by zero
-- checked "0"
  • Integer.parseInt("abc") mətni ədədə çevirə bilmir və NumberFormatException atır.
  • Tam ədədin sıfıra bölünməsi ArithmeticException yaradır. (Maraqlıdır ki, 100.0 / 0 istisna atmır və Infinity verir.)
  • e.getMessage() istisnanın mesajını qaytarır. Proqram istisnadan sonra dayanmadı — dövr növbəti qiymətlə davam etdi.
  • finally hər üç halda işlədi.

Yoxlanılan və yoxlanılmayan istisnalar

Bütün istisnaların ümumi valideyni Throwable-dır. Ondan Error (JVM-in ciddi problemləri, məsələn, yaddaşın bitməsi — onları adətən tutmurlar) və Exception törəyir. Exception-ın isə xüsusi bir qolu var — RuntimeException. Bu bölgü Java-nın unikal qaydasını müəyyən edir:

XüsusiyyətYoxlanılan (checked)Yoxlanılmayan (unchecked)
Kimdən törəyirException (amma RuntimeException yox)RuntimeException
Kompilyator tələb edir?bəli: tut və ya throws ilə elan etxeyr
Adətən nə deməkdirproqramdan asılı olmayan problemproqramçının səhvi
NümunələrIOException, FileNotFoundExceptionNullPointerException, ArithmeticException, IllegalArgumentException

Məsələn, new FileReader("data.txt") yazıb onu try içinə almasan, kod kompilyasiya olunmayacaq: unreported exception FileNotFoundException; must be caught or declared to be thrown. Kompilyator sanki deyir: «Fayl olmaya bilər — bu halda nə edəcəyini qabaqcadan düşün».

throw, throws və öz istisnaların

İstisnanı özün də ata bilərsən: throw new IllegalArgumentException("..."). Bu, metodun yanlış məlumat qəbul etməsinin qarşısını almağın ən yaxşı yoludur. Öz istisna sinfini yaratmaq üçün Exception (yoxlanılan) və ya RuntimeException (yoxlanılmayan) sinfindən törəmə sinif yaz. Yoxlanılan istisna atan metod bunu başlığında throws ilə elan etməlidir.

Java
public class Main {
    static void setAge(int age) {
        if (age < 0 || age > 150) {
            throw new IllegalArgumentException("Invalid age: " + age);
        }
        System.out.println("Age set to " + age);
    }

    public static void main(String[] args) {
        try {
            setAge(25);
            setAge(-3);
            setAge(40);
        } catch (IllegalArgumentException e) {
            System.out.println("Error: " + e.getMessage());
        }
        System.out.println("Program continues");
    }
}
Gözlənilən nəticə
Age set to 25
Error: Invalid age: -3
Program continues

setAge(40) heç vaxt çağırılmadı: setAge(-3) istisna atan kimi try bloku dayandı və idarəetmə catch-ə keçdi. İndi isə öz yoxlanılan istisnamızı yaradaq — pul kisəsində pul çatmayanda:

Java
public class Main {
    public static void main(String[] args) {
        Wallet wallet = new Wallet(30);
        try {
            wallet.pay(12);
            wallet.pay(25);
        } catch (InsufficientFundsException e) {
            System.out.println(e.getMessage());
            System.out.println("Missing: " + e.getMissing() + " AZN");
        }
    }
}

class InsufficientFundsException extends Exception {
    private final double missing;

    InsufficientFundsException(double missing) {
        super("Not enough money in the wallet");
        this.missing = missing;
    }

    double getMissing() { return missing; }
}

class Wallet {
    private double balance;

    Wallet(double balance) { this.balance = balance; }

    void pay(double amount) throws InsufficientFundsException {
        if (amount > balance) {
            throw new InsufficientFundsException(amount - balance);
        }
        balance -= amount;
        System.out.println("Paid " + amount + ", left " + balance);
    }
}
Gözlənilən nəticə
Paid 12.0, left 18.0
Not enough money in the wallet
Missing: 7.0 AZN

Əsas fikirlər

  • İstisna normal axını pozan hadisədir; tutulmazsa, proqram dayanır və stek izi çap olunur.
  • try təhlükəli kodu, catch müəyyən tipli istisnanı tutur, finally isə hər zaman icra olunur.
  • Yoxlanılan istisnaları (IOException) tutmaq və ya throws ilə elan etmək məcburidir; RuntimeException törəmələri isə yoxlanılmır.
  • throw new ... istisnanı atır; öz istisnan üçün Exception və ya RuntimeException-dan törəyən sinif yaz.
  • Boş catch bloku yazma — xəta haqqında məlumat itir.

Özünü yoxla

10 sual. Hər düzgün cavab XP qazandırır.

1 / 10
finally bloku nə vaxt icra olunur?