İçeriğe geç

Değişmez Sınıf Tasarlamak — Bir Kez Kur, Hep Güven

Orta 9 dk Çok sık karşılaşılır

Önce şunu oku: Object Sınıfı — Her Nesnenin Ortak Mirası , final ve static — Kilitli Olan ve Ortak Olan

30 saniyede özet

Değişmez bir nesne kurulduktan sonra hiç değişmez; değişiklik yeni bir nesne üretir. Tarifi kısadır: final sınıf, private final alanlar, setter yok, değişebilen girdilerin kopyası. Karşılığında güvenle paylaşılır.

Bir müzede vitrindeki tabloya kimse dokunamaz. Onu yüzlerce kişi aynı anda izler ve hiçbiri ötekinin gördüğünü bozamaz.

Bazı nesneler de böyle olmalı: kurulduktan sonra hiç değişmeyen, herkesin gönül rahatlığıyla paylaştığı nesneler.

Değişmez nesne bir vitrinde durur: değişiklik yeni bir nesne üretir, eskisi aynen kalır.
Adım adım oku
  1. Tutar nesnesi bir vitrinde duruyor: 100 TRY.
  2. Onu değiştirmek isteyen bir setter yok; deneme geri döner.
  3. arti(50) çağrısı yeni bir Tutar üretir: 150 TRY.
  4. Eski tutar hâlâ 100; onu paylaşan herkes güvende.
  1. Bayt: Bir tutar nesnesini iki hesaba verdim. Biri değiştirdi, öteki de değişmiş!

  2. Sen: Aynı nesneyi paylaşıyorlardı yani.

  3. Bayt: Evet. Nesne değişebildiği için paylaşmak tehlikeliydi.

  4. Bayt: Değişmez yaparsak paylaşmak tamamen güvenli olur. Tarifi beş adım.

Değişmez nesne ne demek?

Bir immutableOluşturulduktan sonra içi değişmeyen nesne. Anahtar olarak güvenlidir, çünkü hashCode'u hiç değişmez.Sözlükte gör → nesne kurulduğu andaki hâlini sonsuza kadar korur. String, BigDecimal, LocalDate ve Integer böyledir.

Bu nesnelerin “değiştiren” metotları aslında yeni bir nesne döndürür: tarih.plusDays(1) eski tarihi değiştirmez. Böylece bir nesneyi kime verirsen ver, geri geldiğinde aynı kalmıştır.

Kafam karıştı, daha basit anlat

Değişmez nesne bir fotoğraf gibidir: çekildiği an donmuştur. Farklı bir hâl istiyorsan yeni bir fotoğraf çekersin; eskisi albümde aynen durur.

Hızlı kontrolBaşlangıç

Program ne yazdırır?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.
Tarih.java
1LocalDate vade = LocalDate.of(2026, 9, 1);
2vade.plusDays(30);
3System.out.println(vade);
Java 21UTF-8LF

Beş adımlık tarif

Kendi değişmez sınıfını yazmak için beş kural yeter:

  1. Sınıfı final yap. Alt sınıf değişebilen bir sürüm yazamasın.
  2. Alanları private final yap. Bir kez atanır, dışarıdan görünmez.
  3. Setter yazma. Değişiklik isteyen metot yeni bir nesne döndürsün.
  4. Kurucuda kuralı kontrol et. Geçersiz nesne hiç doğmasın.
  5. Değişebilen girdileri ve çıktıları kopyala. Buna defensive copyDışarıdan alınan ya da dışarıya verilen değiştirilebilir bir nesnenin kopyasını kullanmak; böylece başkasının referansı iç durumu değiştiremez.Sözlükte gör → denir.
Değişmez bir Tutar
public final class Tutar {
private final BigDecimal deger;
private final String paraBirimi;
public Tutar(BigDecimal deger, String paraBirimi) {
if (deger.signum() < 0) throw new IllegalArgumentException("Negatif olamaz");
this.deger = deger;
this.paraBirimi = paraBirimi;
}
public Tutar arti(Tutar diger) { // setter değil: yeni nesne
return new Tutar(deger.add(diger.deger), paraBirimi);
}
}
Kafam karıştı, daha basit anlat

Kapıyı kilitle (final sınıf), çekmeceleri kilitle (private final), anahtar dağıtma (setter yok). Değişiklik istenirse yeni bir kutu hazırla ve onu ver.

Hızlı kontrolOrta

Değişmez bir sınıf yazarken sınıfı neden `final` yaparsın?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Değişmez bir Tutar sınıfında değeri artırmak gerekiyor. En uygun yol hangisi?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Satır satır: record da delinebilir

record alanları final yapar ve setter üretmez. Ama bir alan değişebilen bir liste ise ne olur?

Sepet adında, bir ürün listesi taşıyan bir record var. Değişebilen bir ArrayList verip sepeti kurduktan sonra aynı listeye `add("elma")` dersen sepetin içi değişir mi? Cevabı göster

Değişir. record listenin kendisini değil, listeye giden oku saklar. Dışarıda kalan aynı ok üzerinden liste değişince sepetin gördüğü liste de değişir.

Oku değil, kopyayı sakla

Sepet.java
1record Sepet(List<String> urunler) {
2 Sepet {
şu an çalışan satır urunler = List.copyOf(urunler);
4 }
5}
6
7List<String> liste = new ArrayList<>(List.of("ekmek"));
8Sepet sepet = new Sepet(liste);
9liste.add("elma");
10System.out.println(sepet.urunler());

Debug

Adım 1/3

kompakt kurucu Gelen listenin değişmez bir kopyası alınır. Sepet artık dışarıdaki listeye bağlı değil.

sepet.urunler
= [ekmek] (kopya)
Java 21UTF-8LF3:1

Sol/sağ ok tuşlarıyla da gezebilirsin.

Sepetin içine kim dokunabilir?

Tohum 608508

record Sepet(List<String> urunler) { Sepet { Kopya yok (oku sakla) } }

    sepet.urunler() = [ekmek]

    Hız
    Adım 0

    Şu an ne oldu?

    Kopya yok (oku sakla)

    Sepet [ekmek] ile kuruldu. İki sızıntı denenecek: içeri ve dışarı.

    Görevler0/3

    • Sepeti, ona hiç dokunmadan değiştiraçık

      İpucu

      Varsayılan ayarlar yeter.

    • Girişi koru ama sepet yine dışarıdan değişsinaçık

      İpucu

      Kopya değişebilir olsun.

    • Sepet baştan sona [ekmek] kalsınaçık

      İpucu

      Değişmez bir kopya.

    Olay günlüğü (0)

    Henüz olay yok. Oynat veya adımla.

    1. Varsayılanla oynat. Kopya yok: dışarıdaki listeye eklenen elma da, erişim metodundan eklenen kola da sepete girdi.
    2. “new ArrayList” seç. Elma artık giremedi, ama erişim metodu değişebilen kopyayı dışarı verdiği için kola girdi.
    3. “List.copyOf” seç. İki deneme de boşa çıktı; sepet [ekmek] kaldı.
    Hızlı kontrolOrta

    Program ne yazdırır?

    Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.
    Sepet.java
    1record Sepet(List<String> urunler) {}
    2
    3List<String> liste = new ArrayList<>(List.of("ekmek"));
    4Sepet sepet = new Sepet(liste);
    5liste.add("elma");
    6System.out.println(sepet.urunler());
    Java 21UTF-8LF

    Neden değer?

    Değişmez bir nesneyi birden çok thread aynı anda kilitsiz okuyabilir; kimse ötekinin altından değiştiremez. HashMap anahtarı olarak da güvenlidir, çünkü hash değeri hiç değişmez.

    Bedeli, her değişiklikte yeni bir nesne üretilmesidir. Küçük değer nesnelerinde bu genelde önemsizdir; çok büyük ve çok sık değişen yapılarda ise ölçüp karar verirsin.

    Kafam karıştı, daha basit anlat

    Değişmeyen bir şeyi paylaşmak risksizdir: kimse onu senin elinden değiştiremez. Karşılığında her değişiklikte yeni bir kopya yaparsın, bu da çoğu zaman ucuzdur.

    Hızlı kontrolOrta

    Değişmez nesnelerin birden çok thread arasında kilitsiz paylaşılabilmesinin sebebi nedir?

    Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

    Bankada değer nesnelerinin çoğu böyle yazılır: bir para transferi talimatı bir kez oluşturulur ve onay, kayıt ve gönderim adımları boyunca hiç değişmez.

    Derinleş · Transfer talimatı: bir kez kur, her adımda güven 2 dosya · ~28 satır · ilk okumada atlayabilirsin
    Proje dosyaları

    src/main/java/com/bank/transfer/ TransferOrder.java Talimat bir record: alanlar final, kurucu kuralı kontrol ediyor ve etiket listesini kopyalıyor.

    src/main/java/com/bank/transfer/TransferOrder.java
    public record TransferOrder(String fromIban, String toIban, BigDecimal amount, List<String> tags) {
    public TransferOrder {
    if (amount.signum() <= 0) {
    throw new IllegalArgumentException("Amount must be positive");
    }
    tags = List.copyOf(tags); // our own immutable copy, not the caller's list
    }
    // A "change" returns a new order; the original is untouched.
    public TransferOrder withTag(String tag) {
    List<String> more = new ArrayList<>(tags);
    more.add(tag);
    return new TransferOrder(fromIban, toIban, amount, more);
    }
    }

    src/main/java/com/bank/ Main.java Değişiklik isteyen metot yeni bir talimat döndürür.

    src/main/java/com/bank/Main.java
    public class Main {
    public static void main(String[] args) {
    List<String> tags = new ArrayList<>(List.of("maas"));
    TransferOrder order = new TransferOrder("TR01", "TR02", new BigDecimal("1000"), tags);
    tags.add("gizli"); // no effect on order
    TransferOrder urgent = order.withTag("acil");
    System.out.println(order.tags()); // [maas]
    System.out.println(urgent.tags()); // [maas, acil]
    }
    }

    Tuzaklar

    final alanı değişmez sanmak. final List<String> yalnızca oku kilitler; listenin içi değişir. İçerik de sabit kalsın istiyorsan kopyasını al ve değişmez bir tip kullan.

    İç diziyi dışarı vermek. Bir getter iç diziyi ya da değişebilen listeyi doğrudan döndürürse, alan kişi içini değiştirebilir. Kopya ya da değişmez bir görünüm döndür.

    final olmayan sınıf. Biri sınıftan türeyip değişebilen alanlar ekleyebilir ve senin sınıfın gibi davranarak dolaşabilir. Sınıfı final yap ya da record kullan.

    Hızlı kontrolOrta

    Bu sınıf değişmez olarak tasarlandı ama bir servis kurulmuş bir ekstrenin hareketlerini değiştirebiliyor. Deliğin kaynağı hangi satır?

    Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

    Hatalı satıra dokun, sonra kontrol et.

    Ekstre.java
    Java 21UTF-8LF

    Kendini sına

    Şimşek turu1/4

    Değişmez bir nesnenin değiştiren metotları yeni bir nesne döndürür.

    Soru 1/3Başlangıç

    Her tipi değişmez ya da değişebilen olarak ayır.

    Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

    Sınıflandırılmamış

    Değişmez

    Kurulduktan sonra hiç değişmez.

      Değişebilen

      İçi sonradan değiştirilebilir.

        Aklında kalacak üç şey

        1. 1 Değişmez bir nesne kurulduktan sonra hiç değişmez; bir değişiklik istendiğinde yeni bir nesne döndürülür.
        2. 2 Tarif: final sınıf, private final alanlar, setter yok, kurucuda kural kontrolü ve değişebilen her girdinin ya da çıktının kopyası.
        3. 3 record da içindeki listeyi korumaz; kompakt kurucuda List.copyOf ile kopyalamadıkça dışarıdan değiştirilebilir.
        Sonraki kapı Hesap ekranı kapandı ama hesap bellekten hiç gitmedi. Onu küçük bir hatırlatıcı mı tutuyor? İç İçe Sınıflar — static, Inner, Anonim ve Yerel · 9 dk

        4 kart sonraki derste seni bekliyor

        0/3 kart bu dersten toplandı