---
title: "Java Sealed Class'lar ve Kapsamlı Desen Eşleştirme (Exhaustive Pattern Matching)"
url: https://blog.edumints.com/java-sealed-class-lar-ve-kapsamli-desen-eslestirme-exhaustive-pattern
category: "Yazılım"
date: 2026-10-19T09:05:24.516Z
publisher: Edumints Blog
lang: tr-TR
source_name: "Hacker News"
source_url: https://neilmadden.blog/2026/04/24/java-sealed-classes-and-exhaustive-pattern-matching/
---

# Java Sealed Class'lar ve Kapsamlı Desen Eşleştirme (Exhaustive Pattern Matching)

Java 17 ile tanıtılan **sealed classes** (mühürlü sınıflar), bir arayüzün (interface) veya temel sınıfın izin verilen alt tiplerini açıkça listelemenize olanak tanır. Örneğin, mühürlü bir arayüz ve `record` yapılarını kullanan basit bir örneğe bakalım (açık bir izin listesi verilmediğinde iç sınıflar örtük olarak izin verilen alt tiplere eklenir):

```java
public sealed interface SealedType {
    record TypeA() implements SealedType {}
    record TypeB() implements SealedType {}

    static SealedType of(String type) {
        return switch (type) {
            case "A" -> new TypeA();
            case "B" -> new TypeB();
            default -> throw new IllegalArgumentException();
        };
    }
}
```

Cebirsel veri tiplerine (algebraic datatypes) sahip fonksiyonel programlama dillerine aşinaysanız, bunu Haskell veya ML'deki bir veri tipi bildirimine benzetebilirsiniz: `data SealedType = TypeA | TypeB`. Daha sonra bunu basit bir `Main` sınıfında şu şekilde kullanabiliriz:

```java
void main(String[] args) {
    var val = SealedType.of(args[0]);
    System.out.println(switch (val) {
        case SealedType.TypeA() -> "A";
        case SealedType.TypeB() -> "B";
    });
}
```

Burada dikkat edilmesi gereken önemli nokta, `main` metodumuzdaki `switch` ifadesine bir `default` dalı eklemek zorunda kalmamamızdır. Bunun nedeni, mühürlü sınıfların (ve enum'ların) **kapsamlılık kontrolünü (exhaustiveness checking)** etkinleştirmesidir: derleyici olası tüm durumların ne olduğunu tam olarak bilir ve hepsini kapsayıp kapsamadığınızı denetleyebilir. Tüm durumları ele aldıysanız `default` dalına ihtiyacınız yoktur. Bir durumu unutursanız (ve `default` dalınız yoksa), derleme zamanı hatası alırsınız.

Bu özellik, bir tipin tüm kullanımlarının olası her durumu kapsamasından emin olmak istediğinizde harikadır; ancak yeni bir tür **geriye dönük uyumsuz değişiklik (breaking change)** ortaya çıkarır: mühürlü bir sınıfa veya arayüze yeni bir alt tip eklemek, bu kodu kullanan istemcileri bozabilir. Örneğin, örneğimize yeni bir `TypeC` durumu eklemek, eksik durum nedeniyle `main` metodunun derlenmemesine yol açacaktır. Dolayısıyla, API'nizde mühürlü bir tipi dışa açıyorsanız, yeni bir alt tip eklemek SemVer (Anlamsal Sürümleme) takip ediyorsanız ana sürüm (major version) artışını gerektiren kırıcı bir değişikliktir.

## Derleme Zamanı Hatası mı, Çalışma Zamanı Hatası mı?

Java, tüketici kodu (bu örnekte `main`) derlediğinizde kapsamlı olmayan bir `switch` için derleme zamanı hatası üretse de, mühürlü tip değiştiğinde tüketici yeniden derlenmezse bunu yapamaz. Örneğin, `SealedType` yapımızı başka bir durumla genişlettiğimizi varsayalım:

```java
public sealed interface SealedType {
    record TypeA() implements SealedType {}
    record TypeB() implements SealedType {}
    record TypeC() implements SealedType {}

    static SealedType of(String type) {
        return switch (type) {
            case "A" -> new TypeA();
            case "B" -> new TypeB();
            case "C" -> new TypeC();
            default -> throw new IllegalArgumentException();
        };
    }
}
```

Eğer sadece `SealedType.java` dosyasını yeniden derler ve `Main` sınıfını yeniden derlemezsek, yeni durumu tetiklediğimizde bir çalışma zamanı istisnası (runtime exception) ile karşılaşırız:

```text
% java Main C
Exception in thread "main" java.lang.MatchException
    at Main.main(Main.java:3)
```

Burada yeni `MatchException` hatasının fırlatıldığını görüyoruz. Javadoc belgeleri, ayrı derleme (separate compilation) kaynaklı bu potansiyel soruna ve desenlerdeki `null` değerlerle ilgili bazı uç durumlara dikkat çekmektedir. Dolayısıyla, mühürlü sınıfları kullanmanın yeni bir durum eklendiğinde tüm tüketicileri güncellemeyi statik olarak garanti edeceğini umuyorsanız, her şeyi yeniden derlemediğiniz sürece bu geçerli değildir.

## Sonuçlar ve Pratik Çıkarımlar

Buradan çıkarılabilecek en temel sonuç, mühürlü tiplerin (sealed types) muhtemelen bir bileşenin **iç 구현 (implementation)** katmanında en faydalı olduğu, ancak bileşenin sunduğu **açık API (public API)** içinde dışarıya açıldığında daha az kullanışlı olduğudur. 

Yazılım geliştirme pratiği açısından şu çıkarımları dikkate almak faydalı olacaktır:
- **Modül İçi Güvenlik:** Aynı derleme birimi veya mikroservis içinde domain modellerini temsil ederken `sealed` arayüzler harika bir tip güvenliği sağlar.
- **Kütüphane Tasarımı:** Dış dünyaya açılan SDK veya kütüphanelerde `sealed` tipler kullanmak, gelecekteki genişletmeleri zorlaştırır ve ikili uyumluluk (binary compatibility) aşamasında `MatchException` riskini doğurur. Açık API'lerde tüketicileri `default` dalı kullanmaya teşvik etmek veya geleneksel arayüz tasarımlarına bağlı kalmak daha güvenli bir yaklaşımdır.

---

**Kaynak:** Hacker News (https://neilmadden.blog/2026/04/24/java-sealed-classes-and-exhaustive-pattern-matching/)
**Yayıncı:** [Edumints Blog](https://blog.edumints.com) · Alıntılarken bu URL'ye bağlantı verin: https://blog.edumints.com/java-sealed-class-lar-ve-kapsamli-desen-eslestirme-exhaustive-pattern
