Tarihçe
Switch yapısı, C tarzı kontrol akış ifadesinden, Java 14'te değer döndüren tam bir ifadeye dönüşmüştür. Java 17 ile birlikte, mirası kısıtlamak için kapatılmış sınıflar ve arayüzler tanıtılmış ve switch için desen eşleştirme, Java 21'de standartlaştırılmadan önce bir önizleme özelliği olarak ortaya çıkmıştır. Bu evrim, switch'i ayrı sabitlere dayanan basit bir atlama tablosundan, bir ifade olarak kullanıldığında tamamlanmayı garanti etmesi gereken karmaşık bir desen eşleştirme mekanizmasına dönüştürdü.
Problemin Tanımı
Switch, bir ifade olarak çalıştığında (ok sözdizimini -> veya yield kullanarak), Java'nın statik tip sistemi gereksinimlerini karşılamak için mümkün olan her girdi için bir değer üretmelidir. Geleneksel switch ifadelerinin, işlenmemiş durumları sessizce atlayabilmesi veya düşmesine izin verebilmesi gibi, bir ifade kesinlikle her yürütme yolunun bir değer döndüreceğinden emin olmalıdır. Kapatılmış hiyerarşiler, tüm izin verilen alt türleri açıkça sıralar ve bu da derleme zamanında tamamlanmayı teorik olarak doğrulayan kapalı bir evren yaratır. Derleyici, kapalı bu dünyayı açık desenlerle (tip desenleri veya null durumları gibi) uzlaştırmak zorundadır, böylece örtüşmemiş tipler yüzünden çalışma zamanında MatchException meydana gelmez.
Çözüm
Derleyici, atıf aşamasında egemenlik ve eksiklik analizi gerçekleştirir. Kapatılmış bir sınıfın izin bülteni, sonlu, kapalı bir tip kümesi olarak değerlendirilir. Switch'deki her desen için, eşleşen tipler izin verilen tipler evreninden çıkarılır. Eğer son desenden sonra hala eşleşmemiş bir izin verilen alt tür kalırsa ve koşulsuz default ya da toplam tip deseni yoksa, derleyici kodu bir hata ile reddeder. Bu analiz, özel desenlerin daha genel olanların önünde gelmesi gerektiği gibi desen egemenlik kurallarına saygı gösterir ve null girişleri tip desenlerinden ayrı olarak ele almak için sentetik bir mekanizma oluşturur.
sealed interface Payment permits Credit, Debit, Crypto {} record Credit() implements Payment {} record Debit() implements Payment {} record Crypto() implements Payment {} // Crypto durumu eksikse derleme zamanı hatası alırsınız double fee = switch (payment) { case Credit c -> 0.02; case Debit d -> 0.01; // Crypto durumu eksik olduğunda: "switch ifadesi tüm olası değerleri kapsamaz" };
Problem Tanımı
Bir ödeme işleme mikroservisinde, ücretleri araç türlerine göre hesaplamamız gerekiyordu: Credit, Debit, BankTransfer ve Crypto. Alan modeli tam olarak bu dört uygulamayı izin veren bir kapatılmış arayüz PaymentInstrument kullandı. Bir junior geliştirici, ücret hesaplayıcısını bir switch ifadesi kullanarak uyguladı ancak istemeden Crypto durumunu atladı, bunun sıfır döndüreceğini varsayarak. Kripto para ödemeleri üretim aşamasında etkinleştirildiğinde, bu atlama çalışma zamanında bir MatchException'a neden oldu, işlem borusunu çökertti ve acil bir geri alma gerektirdi.
Düşünülen Farklı Çözümler
Çözüm A: Varsayılan durum yedeği
Eşleşmemiş herhangi bir aracı ele almak için default -> 0.0 maddesini ekleyebilirdik. Bu yaklaşım, çöküşü önleyerek güvenlik sağlar. Ancak, iş niyetini belirsizleştirir ve işlenmemiş türleri sessizce absorbe eder. Eğer daha sonra kapatılmış hiyerarşiye yeni bir araç türü eklenirse, varsayılan madde bunun ücret hesaplamalarından gizlenmesine neden olur ve potansiyel olarak gelir kaybına veya uyum ihlallerine yol açar.
Çözüm B: Enum Tabanlı Tip Eşlemesi
Enum InstrumentType'a geçiş yapmak, sabit sıralama yoluyla derleme zamanı eksiklik kontrolü sağlamaya olanak tanır. Ancak, bu her ödeme aracının gereksiz tip meta verilerini açığa çıkarması gereken paralel bir taksonomi oluşturur. Kapatılmış sınıfların çok biçimliliğini fedakar, her alt türün benzersiz veri alanlarını (kart numaraları veya blok zincir adresleri gibi) taşıdığı anlamına gelir ve bu da doğal veri denormalizasyonunu zorlayabilir.
Çözüm C: Derleyici Tarafından Zorlanan Kapsayıcı Desenler Switch ifadesini tüm dört izin verilen tip için açık durumlarla tanımlarız, derleyicinin kapatılmış hiyerarşi analizini kullanarak. Bu yaklaşım, eksik durumların derleme hataları olarak ele alınmasını sağlar ve kapatılmış izinler değiştiğinde kod tabanının güncellenmesini zorlar. Çalışma zamanı süprizlerini ortadan kaldırarak, doğrulamayı yapı aşamasına kaydırır.
Seçilen Çözüm ve Sonuç
Çözüm C'yi seçtik ve derleyici uyarılarını, eksiksiz olmayan switch ifadeleri ile ilgili ölümcül hatalar olarak ele almak için yapıyı yapılandırdık. Ürün takımı daha sonra BuyNowPayLater'ı beşinci izin verilen alt tür olarak eklediğinde, CI/CD boru hattı, ücret hesaplamalarının eksik olduğu on yedi yeri hemen tespit etti. Bu, dağıtım öncesinde vergi, uyum ve muhasebe modüllerinde koordineli bir güncelleme gerektirdi, böylece yeni aracın doğru finansal mantığı almasını sağladı. Derleme zamanı garantileri sessiz varsayılanları önler ve dağıtılmış ekipler arasında tip güvenliğini korur.
Null işleme, desen switch'lerinde eksiklik kontrolü ile nasıl etkileşir?
Birçok aday kapatılmış bir sınıfın tüm alt türlerini kapsamanın eksiklik gereksinimlerini karşıladığını yanlış varsayıyor. Ancak, switch ifadeleri null seçimlerini tip desenlerinden farklı olarak ele alır; ayrı bir case null maddesi veya toplam bir desen gereklidir. Açık bir null işlemesi olmadan, derleyici bir sentetik null kontrolü oluşturur ki bu da NullPointerException fırlatır, yani ifade teknik olarak türler için eksiksizdir ama null değeri için değildir.
Kapatılmış bir hiyerarşi üzerinde bir switch'e varsayılan bir madde eklemenin, kapatılmış tiplerin ilkesini nasıl ihlal edebileceği?
Adaylar sıklıkla default'ı savunma kodlama alışkanlığı olarak eklerken, bunun kapatılmış sınıfların kapalı dünya varsayımını zayıflattığını anlamazlar. Bir varsayılan madde, gelecekte izin listesine eklenmiş olan türler dahil her türle eşleşir ve bu da derleme zamanı eksik tanımlama doğrulamasını bir çalışma zamanı toplama alanına dönüştürür. Bu, kapatılmış sınıfların tasarlanma amacına yeniden getirdiği, işlenmemiş yeni türlerin sessizce istenmeyen mantığı yürütmesine izin verdiği kırılganlığı geri getirir.
Kapatılmış bir tip üzerindeki bir switch ifadesi, mevcut modüle görünür olmayan ancak izin verilen bir tip ile karşılaşırsa ne olur? Bu senaryoda, bir kapatılmış sınıfın başka bir paket veya modüldeki paket özel bir alt türü izin vermesi, ancak bu durumun mevcut derleme birimine ihraç edilmemesi nedeniyle görünürlük sınırları söz konusudur. Derleyici, izin verilen tipler kümesinin tamamını sorgulayamayacağı için eksiklik doğrulamasını gerçekleştiremez ve yerel olarak görünen tüm türlerin ele alındığı durumda bile derleme hatası alırsınız. Bunu çözmek için ya varsayılan bir madde eklemek (eksiklik durumunu zayıflatarak) ya da izinleri görünür hale getirmek için JPMS modül ihracatlarını ayarlamak gerekebilir, bu da modül erişilebilirliği ile desen eşleştirme arasındaki etkileşimi vurgular.