---
title: 'İstisna Tasarımı'
source: 'https://academia.sh/tr/kurslar/java-nesne-modeli/istisna-tasarimi'
course: 'Nesneye Dayalı Java'
language: tr
updated: '2026-08-17T18:09:41+00:00'
license: 'CC BY-SA 4.0'
---

# İstisna Tasarımı

Aynı iş üç sözleşmeyle kurulur: denetlenen istisna, denetlenmeyen istisna ve sonuç tipi. Ölçüm çağıran tarafta derleyicinin zorladığı karar noktası sayısını ve boş depoda dikkatsiz çağıranın ne aldığını gösterir; üç sözleşmenin hiçbiri kusuru yok etmez, yalnız göründüğü yeri değiştirir.

Önceki dört ders istisnayı verili aldı: fırlatıldı, bildirildi, yakalandı, bastırıldı.
Hiçbirinde bir olayın **istisnayla mı bildirileceği** sorulmadı. Aynı iş üç ayrı sözleşmeyle
yazılabilir — denetlenen istisna, denetlenmeyen istisna, ya da hiç istisna kullanmayıp sonucu
bir tiple döndürmek.

Bu ders üçünü aynı iş üzerinde kurar: boş olabilen bir depodan öğe almak. Kursun sorusu
burada tasarım sorusuna dönüşür, ama ölçü aynı kalır. Sözleşmeyi seçen, çağıranın ne yapmak
**zorunda** olduğunu seçer; ve zorlamayı yapan taraf her zaman derleyicidir.

## Derleyicinin Zorladığı Karar Noktası

- **GN27** — Üç sözleşme aynı depo üzerinde, aynı üç katmanlı çağrı zinciriyle ölçülür:
  `ic` işi yapar, `orta` onu çağırır, `dis` da `orta`yı.
- **GN28** — Sekiz deneme, bildirimin üç noktadan hangilerine konduğu kümesidir. Sonuç tipi
  için konulacak bir bildirim olmadığından o satırın alt küme sayımı boş bırakılır.

```java
// Olcek.java — ortak ölçüm çekirdeği: verilen kaynağı derler
import java.io.PrintWriter;
import java.io.Writer;
import java.lang.classfile.*;
import java.nio.file.*;
import java.util.spi.ToolProvider;

class Olcek {
    static ClassModel derle(String kaynak, String sinif) throws Exception {
        Path d = Files.createTempDirectory("olcek");
        Path k = d.resolve(sinif + ".java");
        Files.writeString(k, kaynak);
        PrintWriter bos = new PrintWriter(Writer.nullWriter());
        if (ToolProvider.findFirst("javac").orElseThrow()
                .run(bos, bos, "-d", d.toString(), k.toString()) != 0)
            throw new IllegalStateException("derlenmedi: " + sinif);
        return ClassFile.of().parse(d.resolve(sinif + ".class"));
    }
}
```

```java
// Zorlama.java — üç sözleşme çağıran zincirinde kaç noktayı zorluyor
public class Zorlama {
    static final String TIPLER = """
        class Olay extends Exception { Olay(String m) { super(m); } }
        class SessizOlay extends RuntimeException { SessizOlay(String m) { super(m); } }
        record Sonuc(String deger, String hata) { }
        class Depo {
            String denetlenen() throws Olay { throw new Olay("bos"); }
            String denetlenmeyen() { throw new SessizOlay("bos"); }
            Sonuc sonuc() { return new Sonuc(null, "bos"); }
        }
        """;

    static String zincir(String tip, String cagri, String[] bildirim) {
        return TIPLER + "class C {\n"
                + "    static " + tip + " ic(Depo d) " + bildirim[0]
                + " { return d." + cagri + "(); }\n"
                + "    static " + tip + " orta(Depo d) " + bildirim[1] + " { return ic(d); }\n"
                + "    static " + tip + " dis(Depo d) " + bildirim[2] + " { return orta(d); }\n}\n";
    }

    static boolean derlenirMi(String kaynak) {
        try {
            Olcek.derle(kaynak, "C");
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    static void olc(String ad, String tip, String cagri, String bildirim) {
        boolean dokunulmamis = derlenirMi(zincir(tip, cagri, new String[] {"", "", ""}));
        int enAz = -1, gecen = 0;
        for (int m = 0; m < 8; m++) {
            String[] b = new String[3];
            int nokta = 0;
            for (int i = 0; i < 3; i++) {
                boolean var = (m >> i & 1) == 1;
                b[i] = var ? bildirim : "";
                if (var) nokta++;
            }
            if (derlenirMi(zincir(tip, cagri, b))) {
                gecen++;
                if (enAz < 0 || nokta < enAz) enAz = nokta;
            }
        }
        System.out.printf("%-16s %-20s %-10d %s%n", ad,
                dokunulmamis ? "derlendi" : "derlenmedi", enAz,
                bildirim.isEmpty() ? "-" : gecen + " / 8");
    }

    public static void main(String[] args) {
        System.out.printf("%-16s %-20s %-10s %s%n",
                "sozlesme", "dokunulmamis zincir", "en az nokta", "derlenen alt kume");
        olc("denetlenen", "String", "denetlenen", "throws Olay");
        olc("denetlenmeyen", "String", "denetlenmeyen", "throws SessizOlay");
        olc("sonuc tipi", "Sonuc", "sonuc", "");
    }
}
```

```
sozlesme         dokunulmamis zincir  en az nokta derlenen alt kume
denetlenen       derlenmedi           3          1 / 8
denetlenmeyen    derlendi             0          8 / 8
sonuc tipi       derlendi             0          -
```

İlk satır denetlenen istisnanın çağırana yazdığı bedeli sayıyor. Hiçbir yere dokunulmamış
zincir derlenmiyor, ve zinciri derlenir kılan en küçük bildirim kümesinin büyüklüğü **üç** —
yani her katman. Sekiz alt kümeden yalnız **biri** derleniyor: hepsinin bildirdiği küme.
Zorunluluk aradaki bir katmanda durdurulamaz, çünkü bir katman bildirmezse onu çağıran
katman istisnanın varlığını hiç öğrenemez.

İkinci ve üçüncü satırlar sıfır veriyor. Denetlenmeyen istisnada zincire hiç dokunulmadan
derleniyor; sekiz alt kümenin sekizi de geçerli, yani bildirim tümüyle isteğe bağlı. Sonuç
tipinde ise konulacak bir bildirim bile yok.

Buradan ölçülmüş bir karşılaştırma çıkıyor. Denetlenen istisna, hata yolunun varlığını
**zincirin her katmanına yazdırır**; bu bir belgelendirmedir ve derleyici tarafından
uygulanır. Diğer iki sözleşmede hata yolu ara katmanların hiçbirinde görünmez. Ne var ki
zorlanan şey yalnız **bildirmektir**, işlemek değil — ve bir sonraki ölçüm bunun ne anlama
geldiğini gösteriyor.

## Aynı İş, Üç Sözleşme

- **GN29** — Her sözleşme için iki çağıran yazılır: derleyicinin kabul ettiği en kısa yazım
  ile hata yolunu gerçekten işleyen yazım. İkisi de aynı boş depoyla ve aynı dolu depoyla
  çalıştırılır.
- **GN30** — Çağıranın sonucundan yalnız dönen değer ya da çıkan istisnanın sınıf adı
  basılır.

```java
// Sozlesme.java — aynı iş üç sözleşmeyle, dikkatsiz ve dikkatli çağıranla
import java.util.function.Function;

class Olay extends Exception {
    Olay(String m) { super(m); }
}

class SessizOlay extends RuntimeException {
    SessizOlay(String m) { super(m); }
}

record Sonuc(String deger, String hata) { }

class Depo {
    private final String oge;

    Depo(String oge) { this.oge = oge; }

    String denetlenen() throws Olay {
        if (oge == null) throw new Olay("bos depo");
        return oge;
    }

    String denetlenmeyen() {
        if (oge == null) throw new SessizOlay("bos depo");
        return oge;
    }

    Sonuc sonuc() {
        return oge == null ? new Sonuc(null, "bos depo") : new Sonuc(oge, null);
    }
}

public class Sozlesme {
    static String dikkatsizDenetlenen(Depo d) {
        try {
            return d.denetlenen();
        } catch (Olay e) {
            return "";
        }
    }

    static String dikkatliDenetlenen(Depo d) {
        try {
            return d.denetlenen();
        } catch (Olay e) {
            return "yedek (" + e.getMessage() + ")";
        }
    }

    static String dikkatliDenetlenmeyen(Depo d) {
        try {
            return d.denetlenmeyen();
        } catch (SessizOlay e) {
            return "yedek (" + e.getMessage() + ")";
        }
    }

    static String dikkatliSonuc(Depo d) {
        Sonuc s = d.sonuc();
        return s.hata() == null ? s.deger() : "yedek (" + s.hata() + ")";
    }

    static String calistir(Function<Depo, String> f, Depo d) {
        try {
            return "deger \"" + f.apply(d) + "\"";
        } catch (RuntimeException e) {
            return "istisna " + e.getClass().getSimpleName();
        }
    }

    static void satir(String ad, Function<Depo, String> dikkatsiz, Function<Depo, String> dikkatli) {
        Depo bos = new Depo(null), dolu = new Depo("kuzey");
        System.out.printf("%-16s %-26s %-26s %s%n", ad,
                calistir(dikkatsiz, bos), calistir(dikkatli, bos), calistir(dikkatsiz, dolu));
    }

    public static void main(String[] args) {
        System.out.printf("%-16s %-26s %-26s %s%n",
                "sozlesme", "dikkatsiz / bos depo", "dikkatli / bos depo", "dikkatsiz / dolu depo");
        satir("denetlenen", Sozlesme::dikkatsizDenetlenen, Sozlesme::dikkatliDenetlenen);
        satir("denetlenmeyen", d -> d.denetlenmeyen(), Sozlesme::dikkatliDenetlenmeyen);
        satir("sonuc tipi", d -> String.valueOf(d.sonuc().deger()), Sozlesme::dikkatliSonuc);
    }
}
```

```
sozlesme         dikkatsiz / bos depo       dikkatli / bos depo        dikkatsiz / dolu depo
denetlenen       deger ""                   deger "yedek (bos depo)"   deger "kuzey"
denetlenmeyen    istisna SessizOlay         deger "yedek (bos depo)"   deger "kuzey"
sonuc tipi       deger "null"               deger "yedek (bos depo)"   deger "kuzey"
```

İlk sütun üç ayrı kusur biçimi veriyor ve üçü de aynı boş depodan çıkıyor.

Denetlenen sözleşmede dikkatsiz çağıran boş bir dizgi döndürüyor. Derleyici bir yakalama
yazmaya zorladı, ama yazılan yakalamanın içine ne konacağını sormadı; boş bir gövde
zorunluluğu tümüyle karşılıyor. Denetlenen istisnanın güvencesi **hata yolunun
görülmesidir**, işlenmesi değil.

Denetlenmeyen sözleşmede dikkatsiz çağıran çalışma zamanında düşüyor; kusur burada en
gürültülü biçimini alıyor. Sonuç tipinde ise ne derleme zamanında durduruluyor ne de çalışma
zamanında düşüyor; **`null` metnini bir değer olarak** döndürüyor. Üç biçim arasında en
sessiz olanı budur, çünkü hata yolu bir istisna değil, sıradan bir veri hâline gelmiştir.

İkinci sütun üç sözleşmenin ortak noktasını yazıyor: hata yolu gerçekten işlendiğinde üçü de
**aynı sonucu** veriyor. Üçüncü sütun ise ayrımın nerede yaşadığını gösteriyor — depo dolu
olduğunda üç sözleşme ayırt edilemez. Sözleşme seçimi doğru yolda hiçbir şeyi değiştirmez;
tamamı hata yoluna ilişkin bir karardır.

## Kusur Yok Olmaz, Yer Değiştirir

Bu dersin sınırlayıcı ölçümü iki tablonun birlikte okunmasıdır ve üç sözleşmenin hiçbirini
üstün çıkarmaz.

Kusur tektir: boş bir depodan öğe istenmiştir. Üç sözleşme bu kusuru ortadan kaldırmıyor,
yalnız **görüneceği yeri** seçiyor. Denetlenen istisna onu çağıranın derlemesine taşıyor —
üç katman da hata yolunu yazmak zorunda, ama yazdıklarının doğru olması zorunlu değil.
Denetlenmeyen istisna onu çalışma zamanına taşıyor; kaynakta hiçbir katman kirlenmiyor, buna
karşılık hangi çağrının düşebileceği kaynağa bakarak görülemiyor. Sonuç tipi onu veri
katmanına taşıyor; hiçbir yerde düşmüyor, ama yanlış değer akmayı sürdürüyor.

Üç yerin üçünde de bedeli ödeyen ayrı taraflardır: birincisinde yazan, ikincisinde
çalıştıran, üçüncüsünde sonucu okuyan. Bu kursun ilk dersinden beri sürüp gelen ölçü burada
son biçimini alıyor — bir kararın nerede verildiği, kusurun nerede görüneceğini belirler ve
hiçbir seçim kusuru yok etmez.

## Özet

- Denetlenen istisna çağrı zincirinin **her katmanında** bildirim zorunlu kılar: sekiz alt
  kümeden yalnız biri derlenir ve en küçük bildirim kümesinin büyüklüğü üçtür.
- Denetlenmeyen istisna ile sonuç tipi hiçbir noktayı zorlamaz; zincire dokunulmadan
  derlenir ve hata yolu ara katmanların kaynağında görünmez.
- Zorlanan şey bildirmektir, işlemek değil: dikkatsiz çağıran boş bir yakalama yazarak
  zorunluluğu karşılar ve boş bir değer döndürür.
- Aynı boş depo üç ayrı kusur biçimi üretir: boş değer, çalışma zamanı istisnası, ve bir veri
  hâline gelmiş `null`. Hata yolu işlendiğinde üç sözleşme aynı sonucu verir; depo dolu
  olduğunda ayırt bile edilemezler.
- Sınırlayıcı ölçüm: üç sözleşmenin hiçbiri kusuru yok etmez. Kusur tektir ve sözleşme yalnız
  onun görüneceği yeri seçer — derleme, fırlatma ya da okuma.

## Kurs Kapanışı

Kurs tek bir soruyla açıldı: bir ad iki tip taşıdığında, kararı hangisi verir? On üç ders bu
soruyu on üç ayrı dilsel karara sordu ve yanıtı her seferinde çalıştırılmış bir ölçümden
aldı. Toplandığında ortaya tek bir kural çıkıyor: **çağrılan davranış çalışma zamanı tipine,
seçilen ad bildirilen tipe bakar** — ve iki taraf arasındaki sınır sözdiziminde görünmez.

| Ders | Ölçülen karar | Kararı veren taraf | Sınırlayıcı ölçüm |
|---|---|---|---|
| Sınıf, Nesne ve Yapıcı | yapıcı zincirinden çağrılan yeniden tanımlı yöntem | çalışma zamanı tipi | özel ve `final` yöntemde tuzak doğmaz, üçü aynı komuta derlenir |
| Erişim Belirteçleri | görünürlük: 16 çiftin 10'u derlenir | bildirilen tip (derleme zamanı) | üye çalışma zamanında yerinde durur, ayrımı yalnız bir bayrak taşır |
| Kalıtım ve Yeniden Tanımlama | sekiz kararın dördü ve dördü | dördü çalışma zamanı, dördü bildirilen tip | imza denk düşmediğinde yeniden tanımlama doğmaz, karar taraf değiştirir |
| Soyut Sınıflar ve Arayüzler | aynı yeteneğin sekiz kuruluşu, üçünde derleme durur | derleyici, tarafı sormadan | durum taşıyan bir yetenek arayüzle kurulamaz |
| Statik Üyeler ve Başlatma Blokları | statik yöntem seçimi ve sınıf düzeyi durum | bildirilen tip | iki taraf çakıştığında ayrım gözlenemez |
| `final` Anahtar Sözcüğü | yeniden atama, yeniden tanımlama, genişletme kısıtları | bildirilen tip (derleme zamanı) | `final` referans nesneyi dondurmaz |
| İç ve Yerel Sınıflar | üretilen sınıf dosyaları ve gizli alanlar | derleyici, kaynakta yazılmadan | statik iç içe sınıf gizli alan taşımaz |
| Kayıtlar ve Numaralandırmalar | üretilen üyelerin hangi tarafta yanıt verdiği | çalışma zamanı tipi | kaydın koruması sığdır, dizi bileşeni dışarıdan değişir |
| Genel Tipler | tip parametresinin çalışma zamanında bıraktığı | bildirilen tip, tamamen | imza özniteliği kalır: silinen bilgi değil, denetimdir |
| Sınırlı Joker Karakterler | dört kap biçimi × iki işlem, sekizin dördü | bildirilen tip, tamamen | dördünden de `Object` okunur, dördüne de boş değer yazılır |
| İstisna Hiyerarşisi | denetlenen ayrımının zorladığı: dokuz yazımın biri reddedilir | yazımı bildirilen tip, dalı çalışma zamanı tipi | sanal makine bildirimi denetlemez |
| Kaynakla Deneme | kapatma sırası ve bastırılan istisna | derleyici, bildirilen tipe bakarak | bastırma yönü tektir, kapatma gövdedekini bastırmaz |
| İstisna Tasarımı | üç sözleşmenin zorladığı karar noktası: 3, 0, 0 | bildirilen tip (derleme zamanı) | üç sözleşme de kusuru yok etmez, yerini değiştirir |

Tablonun üçüncü sütunu kursun yöntemidir; dördüncü sütun ise her dersin kendi tezini
sınırladığı yerdir. İkisi birlikte okunduğunda kursun asıl iddiası görünüyor: **fark
sözdiziminde görünmez.** `d.ad()` ile `d.etiket` iki
karakterlik bir farkla yazılır ve ayrı taraflardan yanıt alır; `Depo<Ust>` ile `Depo<String>`
ayrı yazılır ve tek bir sınıf olur; `throws` bildirimi kaynakta durur ve çalışma zamanında
denetlenmez.

İkinci okuma genelliklerden geliyor ve son beş dersin ortak dersidir. Bir denetim derleme
zamanına taşındığında ortadan kalkmaz, yalnız **yer değiştirir**; ve o denetimi atlatan bir
yol açıldığında kusur, üretildiği yerde değil, çok sonra okunduğu yerde görünür. Ham tiple
yazılan bir değer okuyan satırda düşer, kaynakla deneme yazılmadığında istisna kapatma
satırında kaybolur, sözleşme yanlış seçildiğinde kusur veri hâline gelir.

Bu kursta sınıflar hep yalnız çalıştı: bir depo, bir üst sınıf, bir alt sınıf. Sıradaki kurs
olan **Standart Kütüphane ve Akışlar** aynı tipleri koleksiyonların ve akışların içine koyar.
Orada tip parametresi tek bir depoda değil, birbirine zincirlenen işlemlerde taşınır; ve
"kararı hangi taraf verdi" sorusu yeniden sorulabilir hâle gelir, çünkü bir akışın her
halkası kendi bildirilen tipini taşır.
