Eğitim Portalı/Java/Hata Yönetimi (Exceptions)
Java01-java/07-hata-yonetimi

Hata Yönetimi (Exceptions)

Hiçbir program kusursuz bir dünyada çalışmaz: dosya bulunamaz, ağ kopar, kullanıcı beklenmedik veri girer, sıfıra bölünür. İyi bir yazılımcı bu durumları yok saymaz; onları öngörür ve zarifçe ele alır. Java'da bunun a…

Hata Yönetimi (Exceptions)

Hiçbir program kusursuz bir dünyada çalışmaz: dosya bulunamaz, ağ kopar, kullanıcı beklenmedik veri girer, sıfıra bölünür. İyi bir yazılımcı bu durumları yok saymaz; onları öngörür ve zarifçe ele alır. Java'da bunun aracı exception (istisna) mekanizmasıdır. Amaç, program bir sorunla karşılaştığında çökmek yerine kontrollü biçimde tepki vermesidir.

try, catch, finally

Riskli kodu bir try bloğuna koyarız; bir hata oluşursa akış ilgili catch bloğuna atlar:

try {
    int sonuc = 10 / 0;            // ArithmeticException fırlar
} catch (ArithmeticException e) {
    System.out.println(e.getMessage());
}

catch, yakalamak istediğin exception tipini belirtir. Hata o tipteyse blok çalışır, değilse exception yukarı doğru "kabarır". finally bloğu ise her durumda — hata olsa da olmasa da — çalışır; bu yüzden temizlik/kaynak kapatma işleri için idealdir.

Örnek 1 (./Ornek1.java) en sık karşılaşacağın ArithmeticException, NullPointerException ve ArrayIndexOutOfBoundsException'ı yakalar ve finally'nin davranışını gösterir.

Checked vs unchecked

Java'da exception'lar iki büyük aileye ayrılır:

  • Checked exceptions (Exception soyundan, RuntimeException hariç): Derleyici bunları ele almanı zorunlu tutar. Ya try-catch ile yakalarsın ya da metot imzasında throws ile bildirirsin. Genelde dış dünyayla ilgili, öngörülebilir sorunlardır (dosya yok, ağ hatası).
  • Unchecked exceptions (RuntimeException soyundan): Derleyici zorunlu tutmaz. Genelde programlama hatalarıdır (NullPointerException, IllegalArgumentException, NumberFormatException).

throw ve throws

throw bir exception'ı elle fırlatır; throws ise bir metodun hangi checked exception'ı fırlatabileceğini bildirir:

static void paraCek(double bakiye, double tutar) throws YetersizBakiyeException {
    if (tutar > bakiye)
        throw new YetersizBakiyeException("Yetersiz bakiye");
}

Özel (custom) exception

Kendi anlamlı exception tiplerini tanımlayabilirsin. Exception'dan türetirsen checked, RuntimeException'dan türetirsen unchecked olur. Bu, hataya iş anlamı katar: YetersizBakiyeException, int -1 döndürmekten çok daha açıktır. Örnek 2 (./Ornek2.java) checked/unchecked ayrımını, throw/throws'u ve özel bir exception'ı bir banka senaryosunda gösterir.

try-with-resources

Dosya, veritabanı bağlantısı, akış (stream) gibi kaynakları işin bitince kapatmak zorundayız. Bunu finally ile elle yapmak hataya açıktır. Java bunun için temiz bir yol sunar: try-with-resources. Parantez içinde açtığın, AutoCloseable'ı uygulayan kaynaklar, blok bitince (hata olsa bile) otomatik kapatılır:

try (Baglanti b = new Baglanti("db")) {
    b.sorguCalistir("...");
} // b.close() otomatik çağrılır

multi-catch

Birden çok exception tipini aynı şekilde ele alacaksan, tek blokta | ile birleştirebilirsin:

catch (NumberFormatException | ArithmeticException e) { ... }

Örnek 3 (./Ornek3.java) AutoCloseable bir kaynak yazar, try-with-resources ile otomatik kapanışı (hatalı senaryo dahil) ve multi-catch'i gösterir.

İyi uygulama notları

  • Boş catch blokları yazma; hatayı en azından logla. Sessizce yutulan hata, bulunması en zor hatadır.
  • catch (Exception e) gibi çok geniş yakalamalardan, gerçekten gerekmedikçe kaçın.
  • Akışı kontrol etmek için exception kullanma; exception "istisnai" durumlar içindir.
  • Anlamlı mesajlar ve uygun (özel) tipler kullan.

Özet

Riskli kodu try ile sarmayı, catch ile hataya tepki vermeyi, finally ve try-with-resources ile kaynakları güvenle kapatmayı öğrendik. Checked/unchecked ayrımını, throw/throws'u ve özel exception'ları gördük. Artık programların hata karşısında çökmesini değil, kontrollü davranmasını sağlayabilirsin. Sırada, çok sayıda veriyi yönetmenin güçlü yolu: Collections Framework.

Kod Örnekleri(3)

Ornek1

çalıştırılabilir
Ornek1.java
1// Ornek1: try-catch-finally ve yaygın exception türleri.
2// Çalıştırma: java Ornek1.java
3public class Ornek1 {
4
5    public static void main(String[] args) {
6        // --- try-catch: hatayı yakala, program çökmesin ---
7        try {
8            int sonuc = 10 / 0; // ArithmeticException fırlatır
9            System.out.println(sonuc);
10        } catch (ArithmeticException e) {
11            System.out.println("Yakalandı (aritmetik): " + e.getMessage());
12        }
13
14        // --- NullPointerException ---
15        try {
16            String s = null;
17            s.length(); // null üzerinde metot çağrısı
18        } catch (NullPointerException e) {
19            System.out.println("Yakalandı (null): null bir nesnenin metodu çağrıldı.");
20        }
21
22        // --- ArrayIndexOutOfBoundsException ---
23        try {
24            int[] dizi = {1, 2, 3};
25            System.out.println(dizi[5]); // geçersiz indeks
26        } catch (ArrayIndexOutOfBoundsException e) {
27            System.out.println("Yakalandı (indeks): dizi sınırı aşıldı -> " + e.getMessage());
28        }
29
30        // --- finally: hata olsa da olmasa da HER ZAMAN çalışır ---
31        // Kaynak kapatma / temizlik için idealdir.
32        try {
33            System.out.println("\ntry bloğu çalışıyor...");
34            throw new RuntimeException("örnek hata");
35        } catch (RuntimeException e) {
36            System.out.println("catch: " + e.getMessage());
37        } finally {
38            System.out.println("finally: temizlik yapıldı (her durumda çalışır).");
39        }
40
41        System.out.println("\nProgram çökmeden devam etti.");
42    }
43}
Çıktı yerel JDK 21 ile yakalandı — tarayıcıda JVM çalışmaz.

Ornek2

çalıştırılabilir
Ornek2.java
1// Ornek2: checked/unchecked, throw/throws ve özel (custom) exception.
2// Çalıştırma: java Ornek2.java
3public class Ornek2 {
4
5    // throws: bu metot bir checked exception fırlatabilir, çağıran ilgilenmeli.
6    static void paraCek(double bakiye, double tutar) throws YetersizBakiyeException {
7        if (tutar > bakiye) {
8            // throw: bir exception nesnesini elle fırlat.
9            throw new YetersizBakiyeException(
10                    "Yetersiz bakiye: istenen " + tutar + ", mevcut " + bakiye);
11        }
12        System.out.println(tutar + " TL çekildi. Kalan: " + (bakiye - tutar));
13    }
14
15    public static void main(String[] args) {
16        double bakiye = 500;
17
18        // Checked exception derleyici tarafından zorunlu kılınır: ya yakala ya da bildir.
19        try {
20            paraCek(bakiye, 200);
21            paraCek(bakiye, 800); // bu satır YetersizBakiyeException fırlatır
22        } catch (YetersizBakiyeException e) {
23            System.out.println("İşlem reddedildi: " + e.getMessage());
24        }
25
26        // Unchecked (RuntimeException) yakalamak zorunlu değildir ama yakalanabilir.
27        try {
28            int x = Integer.parseInt("abc"); // NumberFormatException (unchecked)
29            System.out.println(x);
30        } catch (NumberFormatException e) {
31            System.out.println("Sayı çevrilemedi: geçersiz format.");
32        }
33    }
34}
35
36// Özel checked exception: Exception'dan türetilir.
37// (RuntimeException'dan türetseydik unchecked olurdu.)
38class YetersizBakiyeException extends Exception {
39    public YetersizBakiyeException(String mesaj) {
40        super(mesaj);
41    }
42}
Çıktı yerel JDK 21 ile yakalandı — tarayıcıda JVM çalışmaz.

Ornek3

çalıştırılabilir
Ornek3.java
1// Ornek3: try-with-resources, AutoCloseable ve multi-catch.
2// Çalıştırma: java Ornek3.java
3public class Ornek3 {
4
5    public static void main(String[] args) {
6        // --- try-with-resources ---
7        // Parantez içinde açılan kaynaklar, blok bitince (hata olsa bile)
8        // OTOMATİK kapatılır. Kaynak, AutoCloseable'ı uygulamalıdır.
9        System.out.println("--- Normal akış ---");
10        try (Baglanti b = new Baglanti("veritabani")) {
11            b.sorguCalistir("SELECT * FROM urun");
12        }
13
14        System.out.println("\n--- Hata olsa bile kapatılır ---");
15        try (Baglanti b = new Baglanti("dosya")) {
16            b.sorguCalistir("HATALI");
17        } catch (RuntimeException e) {
18            System.out.println("Yakalandı: " + e.getMessage());
19        }
20
21        // --- multi-catch: birden çok exception'ı tek blokta yakala ---
22        System.out.println("\n--- multi-catch ---");
23        for (String girdi : new String[]{"10", "abc"}) {
24            try {
25                int n = Integer.parseInt(girdi);
26                System.out.println("100 / " + n + " = " + (100 / n));
27            } catch (NumberFormatException | ArithmeticException e) {
28                System.out.println("'" + girdi + "' için hata: " + e.getClass().getSimpleName());
29            }
30        }
31    }
32}
33
34// AutoCloseable: try-with-resources tarafından otomatik kapatılabilen kaynak.
35class Baglanti implements AutoCloseable {
36    private final String ad;
37
38    Baglanti(String ad) {
39        this.ad = ad;
40        System.out.println("[açıldı] " + ad);
41    }
42
43    void sorguCalistir(String sorgu) {
44        if (sorgu.equals("HATALI")) {
45            throw new RuntimeException("sorgu çalıştırılamadı");
46        }
47        System.out.println("[sorgu]  " + sorgu);
48    }
49
50    @Override
51    public void close() { // blok bitince otomatik çağrılır
52        System.out.println("[kapandı] " + ad);
53    }
54}
Çıktı yerel JDK 21 ile yakalandı — tarayıcıda JVM çalışmaz.