İçeriğe geç

Java 8'den 21'e — Her Özellik Bir Hata Sınıfı

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

30 saniyede özet

Java'nın yeni özellikleri sadece yazıyı kısaltmıyor, derleyicinin senin yerine hata yakalamasını sağlıyor. record, sealed ve pattern matching'in her biri bir hata türünü ortadan kaldırıyor.

Java her sürümde yeni özellikler ekliyor ve liste göz korkutabilir. İşin sırrı basit: her özellik bir hatayı imkânsız hâle getiriyor.

  1. Bayt: Java her sürümde yeni özellik ekliyor. Bunların hepsini nasıl öğreneceğim?!

  2. Sen: Liste gerçekten göz korkutucu.

  3. Bayt: Sır şu: her özellik bir hata türünü imkânsız hâle getiriyor.

  4. Bayt: Yani ezber yok. Her özelliğin hangi hatayı kapı dışarı ettiğini bil, yeter.

Kendin gör

Java 8 → 21 — aynı sınıf, her sürümde bir hata sınıfı eksiliyor

Tohum 6
  • ·Lambda, Stream ve OptionalJava 8
  • ·var ve değiştirilemez koleksiyonlarList.of → Java 9, var → Java 10
  • ·switch ifadesi ve metin bloğuswitch ifadesi → Java 14, metin bloğu → Java 15
  • ·recordJava 16
  • ·sealed ve switch’te pattern matchingsealed → Java 17, switch’te pattern matching → Java 21

Satır

118

Açık cast

6

Null noktası

5

Değiştirilebilir

4

equals / hashCode

Elle yazılmış. Alan eklenince güncellenmezse HashMap araması sessizce bozulur.

Bütünlük denetimi

Yeni bir alt tip sessizce eleniyor — derleyici uyarmaz.

Hız
Adım 0

Şu an ne oldu?

Başlangıç — Java 5 tarzı bir sınıf, 118 satır

6 açık cast, 5 null noktası ve derleyicinin doğrulayamadığı bir dal zinciri var. Bunların hiçbiri stil sorunu değil; her biri bir hata sınıfı.

Aklında kalsın: Sürüm özelliklerini liste olarak saymak yerine her birinin hangi hatayı ortadan kaldırdığını söylemek, konuyu gerçekten bildiğini gösterir.

Olay günlüğü (0)

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

Aynı sınıf, dört farklı hedef sürümde:

  1. Java 8. 118 satırdan 100’e. Cast’ler duruyor, equals elle yazılmış.
  2. Java 17. 38 satır — en büyük tek düşüş record aşamasında. Ama cast zinciri hâlâ orada.
  3. Java 21. 30 satır, 0 cast ve sağdaki iki kutu da yeşil.
  4. default anahtarını aç. Satır sayısı değişmiyor ama bütünlük denetimi kırmızıya dönüyor.
  5. sealed’i kapat. Aynı sonuç, farklı sebeple.

Sağdaki iki kutu dersin özeti: satır sayısı bir ölçüt değil, derleyicinin verdiği garantiler ölçüt.

Hızlı kontrolOrta

Her sınıfı record olmaya uygun olup olmadığına göre yerleştir.

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

Sınıflandırılmamış

record olabilir

Değiştirilemez, kimliği alanlarından gelir

    record olmamalı

    Değişir veya kimliği ayrıdır

      record neden değerli?

      record Circle(double radius) implements Shape {}

      Bu tek satır; equals, hashCode, toString, getter’lar ve constructor’ı senin yerine yazar. Ama asıl kazanç yazmaktan kurtulmak değil.

      Asıl kazanç şu: alan eklediğinde hepsi otomatik güncellenir. Elle yazılmış bir equals’a alan eklemeyi unutmak, HashMap aramasını sessizce bozar.

      Ne zaman kullanılmaz: recordBileşenleri değişmez olan, equals/hashCode/toString'i derleyicinin ürettiği veri taşıyıcısı sınıf.Bileşen eklediğinde equals ve hashCode birlikte güncellenir — elle yazılmış bir equals'a alan eklemeyi unutmak klasik hatadır. Bileşenler final olduğu için record'lar güvenli HashMap anahtarıdır.Sözlükte gör → bir değerdir; değişmez ve alanları aynı olan iki record eşittir, tıpkı iki 5 liralık banknot gibi. Veritabanındaki bir kayıt (JPA entity) ise zamanla değişir ve kimliği id’sindedir, bu yüzden record yapılmaz.

      Kafam karıştı, daha basit anlat

      record, “bu sadece bir değer” demenin kısa yoludur. Karşılaştırma ve yazdırma kodunu Java yazar. Yeni alan eklediğinde onları güncellemeyi unutamazsın.

      Hızlı kontrolBaşlangıç

      Bir `record` senin için hangi üyeleri otomatik üretir?

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

      Derleyici eksik dalı ne zaman yakalar?

      sealed, “bu tipin alt türleri yalnızca bunlar” der. pattern matchingBir değerin şeklini sınayıp aynı anda parçalarına ayırmak. `instanceof` ve `switch` ile gelir; tip kontrolü ve cast'i tek adıma indirir.Sözlükte gör → ile birleşince uzun instanceof zincirleri ortadan kalkar:

      sealed interface Shape permits Circle, Square {}
      double area(Shape shape) {
      return switch (shape) {
      case Circle c -> PI * c.radius() * c.radius();
      case Square q -> q.side() * q.side();
      }; // default yok — ve olmamalı
      }

      Buraya Triangle eklersen derleme hatası alırsın. Derleyici seni eksik daldan haberdar eder.

      Aynı switch'in sonuna bir de `default -> 0;` eklersen ve sonra Triangle'ı eklersen derleyici seni uyarır mı? Cevabı göster

      Hayır. default yeni tipi sessizce yakalar, program derlenir ve Triangle’ın alanı 0 çıkar.

      Aynı yeni tip, iki switch: biri seni uyarır, biri susar.
      Adım adım oku
      1. sealed Shape, alt tiplerinin tam listesini derleyiciye bildirir: Circle ve Square.
      2. Hiyerarşiye yeni bir tip eklenir: Triangle.
      3. default'u olmayan switch artık derlenmez. Derleyici eksik dalı gösterir.
      4. default'u olan switch derlenir ve Triangle'ı sessizce yakalar. Alan 0 çıkar, kimse fark etmez.

      Garanti iki şartı birden ister:

      sealeddefaultDerleyici yeni tipi bulur mu
      ✅yokEvet
      ✅varHayır — default onu yutar
      ❌zorunluHayır

      Simülatördeki 16 kombinasyondan yalnızca biri yeşil. default yazmak, sealed’in verdiği garantiyi kendi elinle kapatmaktır.

      Aşağıda bir bankanın havale ücretini iki dönemin Java’sıyla hesaplıyoruz. FAST, EFT ve SWIFT için tarife aynı; bak hangisi yeni bir tür eklediğinde seni uyarıyor.

      Derinleş · Havale ücreti, iki Java: 8 ve 21 4 dosya · ~67 satır · ilk okumada atlayabilirsin
      Proje dosyaları

      src/main/java/com/bank/transfer/ Transfer.java Sealed arayüz ve record'lar: bankanın üç transfer türü tek yerde, yanında örnek bir tarife.

      src/main/java/com/bank/transfer/Transfer.java
      // Every permitted type is listed, so a switch over Transfer can be exhaustive.
      public sealed interface Transfer permits Fast, Eft, Swift {
      BigDecimal amount();
      }
      record Fast(BigDecimal amount, String toIban) implements Transfer {}
      record Eft(BigDecimal amount, String toIban, boolean afterCutoff) implements Transfer {}
      record Swift(BigDecimal amount, Currency currency, String bic) implements Transfer {}
      // An example tariff, not any real bank's.
      final class Tariff {
      static final BigDecimal FREE_FAST_LIMIT = new BigDecimal("1000.00");
      static final BigDecimal FAST_FEE = new BigDecimal("4.50");
      static final BigDecimal EFT_FEE = new BigDecimal("7.50");
      static final BigDecimal SWIFT_RATE = new BigDecimal("0.001");
      static final BigDecimal SWIFT_MIN_FEE = new BigDecimal("25.00");
      private Tariff() {}
      }

      src/main/java/com/bank/transfer/ TransferFeeJava8.java Şöyle de yazılabilirdi: Java 8 tarzı instanceof zinciri. Bak, sonradan eklenen SWIFT sessizce ücretsiz geçiyor.

      src/main/java/com/bank/transfer/TransferFeeJava8.java
      public class TransferFeeJava8 {
      public BigDecimal fee(Transfer transfer) {
      if (transfer instanceof Fast) {
      Fast fast = (Fast) transfer; // cast after the check
      return fast.amount().compareTo(Tariff.FREE_FAST_LIMIT) <= 0
      ? BigDecimal.ZERO
      : Tariff.FAST_FEE;
      } else if (transfer instanceof Eft) {
      return Tariff.EFT_FEE;
      }
      // Swift arrived later and nobody came back to this chain. It still compiles.
      return BigDecimal.ZERO;
      }
      }

      src/main/java/com/bank/transfer/ TransferFee.java Java 21: guard ve record pattern'li switch; yeni bir transfer türü eklenince derleme burada durur.

      src/main/java/com/bank/transfer/TransferFee.java
      public class TransferFee {
      public BigDecimal fee(Transfer transfer) {
      return switch (transfer) {
      case Fast fast when fast.amount().compareTo(Tariff.FREE_FAST_LIMIT) <= 0 -> BigDecimal.ZERO;
      case Fast fast -> Tariff.FAST_FEE;
      case Eft eft -> Tariff.EFT_FEE;
      case Swift(var amount, var currency, var bic) -> // fee in the transfer's currency
      amount.multiply(Tariff.SWIFT_RATE)
      .setScale(2, RoundingMode.HALF_UP)
      .max(Tariff.SWIFT_MIN_FEE);
      // No default: add a fourth Transfer type and this switch no longer compiles.
      };
      }
      }

      src/main/java/com/bank/transfer/ FeeReceipt.java Text block ile dekont metni, kaçış karakteri olmadan.

      src/main/java/com/bank/transfer/FeeReceipt.java
      public class FeeReceipt {
      // Text block: the indentation of the closing quotes sets the left margin.
      private static final String TEMPLATE = """
      İşlem : %s
      Tutar : %s
      Ücret : %s
      """;
      public static String render(Transfer transfer, BigDecimal fee) {
      String kind = switch (transfer) {
      case Fast fast -> "FAST";
      case Eft eft -> eft.afterCutoff() ? "EFT (ertesi iş günü)" : "EFT";
      case Swift swift -> "SWIFT " + swift.currency().getCurrencyCode();
      };
      return TEMPLATE.formatted(kind, transfer.amount().toPlainString(), fee.toPlainString());
      }
      }

      switch ifadesi.

      // deyim: break unutulursa sessizce alt dala düşer
      switch (kind) { case "circle": label = "Daire"; case "square": ... }
      // ifade: düşmez, değer döndürür, her yol bir değer üretmek zorundadır
      var label = switch (kind) {
      case "circle" -> "Daire";
      case "square" -> "Kare";
      default -> "Bilinmeyen";
      };

      switch deyimi ile switch ifadesi farklı şeylerdir: biri akış kontrolüdür, diğeri bir değer üretir ve derleyici her yolun bir değer döndürdüğünü kontrol eder.

      Kafam karıştı, daha basit anlat

      sealed derleyiciye bütün alt türlerin listesini verir. Sen bir tür eklediğinde, derleyici o türü unutan her switch’i sana gösterir. default yazarsan bu yardımı kapatırsın.

      Hızlı kontrolOrta

      `sealed` bir arayüz, pattern matching switch'e ne kazandırır?

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

      `sealed` bir arayüz üzerinde pattern matching switch yazdınız ve sonuna `default` eklediniz. Yeni bir alt tip eklendiğinde ne olur?

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

      Dönüş tipleri ve tip çıkarımı

      Optional’ın amacı null kontrolünü kısaltmak değil. Amacı “bu metot değer döndürmeyebilir” bilgisini tipe yazmak.

      Optional<User> findByEmail(String email); // ✅ sözleşmeyi anlatır

      İki yaygın yanlış kullanım:

      • Alan olarak. private Optional<String> name; — serialize edilemez, bir katman ekler, hiçbir şey kazandırmaz.
      • Parametre olarak. Çağıranı Optional.of(...) sarmalamaya zorlar. Onun yerine metodu aşırı yükle.

      Ve opt.get() yazıyorsan Optional’ı kullanmıyorsun demektir — orElse, orElseThrow, map veya ifPresent var.

      var.

      var users = new ArrayList<User>(); // tip belli, tekrar yazmaya gerek yok
      var result = service.process(input); // tip belli değil — okuyucu kaybolur

      var derleme zamanında tipi sabitler; hiçbir şey dinamikleşmez. Kural basit: sağ taraf tipi söylüyorsa var kullan, söylemiyorsa yazma.

      Kafam karıştı, daha basit anlat

      Satırın sağ tarafı tipi zaten söylüyorsa var yaz. Okuyan kişi tipi tahmin etmek zorunda kalacaksa tipi açıkça yaz.

      Hızlı kontrolBaşlangıç

      `var` anahtar kelimesi Java'yı dinamik tipli yapar mı?

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

      Hangi sürümde ne geldi

      SürümÖzellikOrtadan kaldırdığı şey
      8Lambda, Stream, OptionalAnonim sınıflar, elle döngü, null dönen aramalar
      9List.of, Map.ofDışarı sızan değiştirilebilir koleksiyonlar
      10varTekrarlanan tip bildirimleri
      14switch ifadesiFallthrough hataları
      15Metin bloğuKaçış karakteriyle dolu SQL/JSON
      16recordElle yazılmış, senkronu bozulan equals/hashCode
      17sealedBilinmeyen alt tipler
      21switch’te pattern matchinginstanceof + cast zinciri, eksik dallar
      21Virtual threadsThread havuzu doygunluğu

      Uzun destekli (LTS) sürümler: 8, 11, 17, 21. Çoğu ekip yalnızca bunlar arasında geçiş yapar, aradaki sürümleri atlar.

      Kendini sına

      Önce hızlı bir ısınma: puan yok, kayıt yok.

      Şimşek turu1/5

      record'ların alanları final'dır; oluşturulduktan sonra değiştirilemez.

      Soru 1/3Orta

      Bu kod ne yazdırır?

      Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.
      Demo.java
      1record Point(int x, int y) {}
      2
      3var map = new HashMap<Point, String>();
      4map.put(new Point(1, 2), "merkez");
      5
      6System.out.println(map.get(new Point(1, 2)));
      7System.out.println(new Point(1, 2) == new Point(1, 2));
      Java 21UTF-8LF

      Aklında kalacak üç şey

      1. 1 Her yeni özellik bir hatayı ortadan kaldırıyor: record elle yazılan equals'ı, switch ifadesi unutulan break'i, sealed ile pattern matching eksik dalı.
      2. 2 record'un değeri kısalık değil: equals ve hashCode alanlarla hep uyumlu kalır. Elle yazılmış sınıfta alan eklenip equals unutulunca HashMap sessizce bozulur.
      3. 3 Derleyicinin eksik dalı yakalaması iki şart ister: sealed bir hiyerarşi ve default'suz bir switch. default yazdığın anda bu yardımı kaybedersin.
      Sonraki kapı İki thread aynı sayacı onar bin kez artırıyor. Sonuç neden yirmi bin çıkmıyor? Race Condition ve Görünürlük · 10 dk

      5 kart sonraki derste seni bekliyor

      0/5 kart bu dersten toplandı

      Bu dersin üstüne kurulanlar

      Bunlar bu dersi temel alıyor; hazır olduğunda devam edebilirsin.