İsimlendirilmiş Değerlerden Oluşan Sabit Bir Küme
Bazı değerler yalnızca küçük ve bilinen bir listenin parçası olarak anlam taşır: haftanın günleri, bir destedeki kâğıt türleri, bir siparişin içinde bulunabileceği durumlar. Bunları int kodlarıyla (0 beklemede, 1 gönderildi) veya metinlerle ("PENDING", "SHIPPED") modelleyebilirsiniz, ama hiçbir şey çağıranı 7 ya da "PNEDING" geçmekten alıkoymaz. Bir enum bu açığı kapatır — türün kendisi yalnızca tanımladığınız değerlere izin verir.
Day bambaşka bir türdür. Day türündeki bir değişken tam olarak bu yedi sabitten birini (veya null) tutabilir, başka hiçbir şeyi tutamaz. Derleyici Day d = "WEDNESDAY"; veya Day d = 2; ifadesini reddeder. İşte tüm amaç bu garantidir.
Her sabit (Day.MONDAY ve diğerleri) bir kez oluşturulan, paylaşılan tek bir örnektir. Yalnızca tek bir MONDAY olduğundan, enum'ları equals yerine == ile karşılaştırırsınız — aynı nesnedirler.
Bir Enum Üzerinde switch Kullanmak
Enum'lar switch ile doğal biçimde uyumludur. Switch içinde her sabitin başına tür adını yazmanıza bile gerek yoktur:
switch içinde case Day.SATURDAY değil, case SATURDAY yazın — Java türü çıkarır. Bir metin veya int üzerinde switch kullanmaya göre en büyük kazanç şudur: daha sonra yeni bir sabit eklerseniz, IDE'niz ve bütünlük denetimleri onu işlemeyi unutan her switch'i işaretleyebilir.
Tüm Sabitler Üzerinde Döngü Kurmak
Her enum otomatik olarak, tüm sabitlerini tanımlanma sırasına göre döndüren statik bir values() metodu ile her sabitin sıfır tabanlı konumunu veren bir ordinal() alır:
name() sabitin tanımlayıcısını bir String olarak verir ve values() menü oluşturmak ya da seçenekler üzerinde döngü kurmak için mükemmeldir. Bir uyarı: ordinal() değerini kalıcı bir yere kaydetmeyin. Birisi sabitleri daha sonra yeniden sıralarsa numaralar kayar ve kayıtlı verileriniz bozulur. ordinal() değerini kararlı bir kimlik değil, bir uygulama ayrıntısı olarak görün.
Enum'lar Gerçek Sınıflardır: Alanlar ve Metotlar
Java enum'larının diğer dillerdeki isimlendirilmiş tamsayı enum'larının ötesine geçtiği yer burasıdır. Her sabit, bir yapıcı aracılığıyla geçirilen veri taşıyabilir ve enum metotlara sahip olabilir. Önce sabitleri listeler, her birine yapıcı argümanlarını verir, ardından bir noktalı virgülden sonra alanları, yapıcıyı ve metotları tanımlarsınız.
Yapıya dikkat edin: sabitler önce gelir ve bir noktalı virgülle biter, ardından sınıfın geri kalanı gelir. Yapıcı örtük olarak private'tır — asla new Planet(...) yazamazsınız, çünkü izin verilen tek örnekler en üstte tanımlananlardır. final alanlar her sabiti değişmez kılar; bu da paylaşılan tekil nesneler için tam olarak istediğiniz şeydir.
Bir Metinden ve Geri
Bir metni eşleşen sabite dönüştürmek için otomatik üretilen valueOf'u kullanın:
valueOf, büyük/küçük harf dahil olmak üzere sabit adını tam olarak eşleştirir ve eşleşme yoksa IllegalArgumentException fırlatır. İşte sık yapılan hata: "shipped", SHIPPED ile eşleşmez. Kullanıcı girdisini veya dış veriyi ayrıştırırken önce büyük/küçük harfi normalleştirin (input.toUpperCase()) ve çağrıyı bir try/catch içine alın, yoksa ilk hatalı değerde program çöker.
Sabite Özgü Davranış
Bazen her sabitin yalnızca farklı veri tutması değil, farklı davranması gerekir. Bir enum'a soyut bir metot verebilir ve her sabitin küçük bir gövdede kendi gerçekleştirimini sunmasını sağlayabilirsiniz:
Buna bazen "sabite özgü metot" deseni denir. Sabit üzerinde devasa bir switch yerine davranışı doğrudan her sabite bağlar — yeni bir işlem eklediğinizde derleyici sizi onun apply'ını tanımlamaya zorlar, böylece hiçbir durumu unutamazsınız.
Ne Zaman Enum'a Başvurmalı
Bir değer doğal olarak küçük, sabit ve derleme zamanında bilinen bir kümenin parçasıysa her zaman bir enum kullanın:
- Bir iş akışındaki durumlar (
PENDING,SHIPPED,DELIVERED). - Kategoriler, modlar veya türler (
READ,WRITE,EXECUTE). - Bir grup
public static final intsabiti tanımlamak istediğiniz her yerde — enum size aynı isimlendirilmiş değerleri artı tür güvenliğini, okunabilir birtoString'i ve bedavadanswitchdesteğini verir.
Açık uçlu ya da çalışma zamanında belirlenen bir küme için (kullanıcı adları, bir veritabanından çekilen ülke listesi) enum kullanmayın. Enum'lar derleme zamanında sabitlenir; küme program çalışırken değişiyorsa, bunun yerine sıradan bir koleksiyon istersiniz.
Sıradaki: Generics
Artık values()'in bir Planet[] döndürdüğünü ve daha önceki sayfalarda List<Shape> kullanımını gördünüz — bu <...> söz dizimi generics, yani Java'nın tam tür güvenliğini korurken birçok tür için çalışan tek bir sınıf veya metot yazma yöntemidir. Sırada, List<String> ve Map<K, V>'nin gerçekte nasıl çalıştığını ve kendi generic türlerinizi nasıl yazacağınızı açacağız.
Sıkça Sorulan Sorular
Java'da enum nedir?
Bir enum, değeri yalnızca sabit ve isimlendirilmiş bir sabitler kümesinden biri olabilen özel bir türdür; örneğin Day.MONDAY veya Status.ACTIVE. Her sabit, enum'ın önceden oluşturulmuş tek bir örneğidir. Enum'lar size tür güvenliği sağlar: Day alan bir metot yalnızca gerçek bir gün alabilir, asla yanlış yazılmış bir metin ya da aralık dışı bir int alamaz.
Java enum'ı alanlara ve metotlara sahip olabilir mi?
Evet. Bir enum tam bir sınıftır. Her sabite yapıcı argümanları verebilir, bunları private final alanlarda saklayabilir ve onları kullanan metotlar ekleyebilirsiniz. Örneğin MERCURY(3.3e23, 2.4e6), enum'ın yapıcısına kütle ve yarıçapı geçirir ve bir surfaceGravity() metodu bu alanlardan hesaplama yapabilir.
Java enum'ında values() ile valueOf() arasındaki fark nedir?
values(), enum'ın tüm sabitlerini tanımlanma sırasına göre bir dizi olarak döndürür; her seçenek üzerinde döngü kurmak için kullanışlıdır. valueOf("NAME") ise tam tersini yapar: adı verilen metinle tam olarak eşleşen sabiti bulur ve eşleşme yoksa IllegalArgumentException fırlatır. İkisi de derleyici tarafından otomatik üretilir.