1. Giriş
Java-da enumerasiyalarla (enum) işləmək üçün xüsusi kolleksiyalar var: EnumSet və EnumMap. Onlar standart kitabxanaya (java.util) daxildir və enum tipləri ilə maksimal səmərəli iş üçün nəzərdə tutulub.
EnumSet və EnumMap daxilən necə işləyir?
EnumSet bit maskası kimi işləyir. Bunu bayraqlar dəsti kimi təsəvvür edin, burada enumerasiyanın hər bir elementi məhz bir bit tutur. Bit aktivdirsə — element çoxluqdadır, deaktivdirsə — yoxdur. Hər şey ədədlər massivində (long[]) saxlanılır və əgər sizin enum-unuzda 64-dən az dəyər varsa, onda bütün dəst cəmi bir ədəddə yerləşir!
EnumMap isə daha da sadədir: bu, dəyərlər massividir və indeks kimi enum elementinin ardıcıl nömrəsi (ordinal) xidmət edir. Adi HashMap<Enum, V> əvəzinə çox yığcam və sürətli bir struktur əldə edirsiniz.
Bu nə verir? Əlavəetmə, silmə və yoxlama əməliyyatları O(1) vaxtda icra olunur. Yaddaş sərfi minimumdur (xüsusən HashSet və HashMap ilə müqayisədə). Elementlər üzərində iterasiya həmişə enum-da elan olunma ardıcıllığına uyğun gedir, bu da nəticəni proqnozlaşdırılan edir.
Nümunə: bu necə görünür
enum Day { MON, TUE, WED, THU, FRI, SAT, SUN }
EnumSet<Day> weekend = EnumSet.of(Day.SAT, Day.SUN);
System.out.println(weekend); // [SAT, SUN]
Çöldən bu, adi bir çoxluqdur. Amma daxilən — iki biti qurulmuş bir ədəd: biri SAT, digəri SUN üçün. FRI əlavə etsəniz — daha bir bit aktivləşəcək. Heç bir hash cədvəli və artıq obyektlər yoxdur.
EnumMap<Day, String> schedule = new EnumMap<>(Day.class);
schedule.put(Day.MON, "Gym");
schedule.put(Day.FRI, "Party");
System.out.println(schedule); // {MON=Gym, FRI=Party}
Burada açarlar (Day) daxili massiv indekslərinə çevrilir, buna görə də giriş massiv elementinə müraciət qədər sürətlidir.
2. İstifadə hallar: bayraqlar, cədvəllər, sonlu avtomatlar
EnumSet: bayraqlar və vəziyyət dəstləri üçün ideal
- Bayraqlar: məhdud sayda seçim üçün “açıq/bağlı” dəstlərinin saxlanması.
- Enum dəyərləri çoxluğu: həftənin günləri, istifadəçi icazələri, tapşırıq vəziyyətləri.
- Sonlu avtomatlar (FSM): icazə verilən keçidləri EnumSet-də saxlamaq rahatdır.
Nümunə: giriş icazələri bayraqları
enum Permission { READ, WRITE, EXECUTE }
EnumSet<Permission> perms = EnumSet.of(Permission.READ, Permission.WRITE);
if (perms.contains(Permission.WRITE)) {
// Yazmağa icazə verilir
}
Nümunə: bəzilərindən başqa bütün dəyərlər
EnumSet<Day> workdays = EnumSet.complementOf(EnumSet.of(Day.SAT, Day.SUN));
System.out.println(workdays); // [MON, TUE, WED, THU, FRI]
EnumMap: enum açarları üçün cədvəllər üçün ideal
- Uyğunluq cədvəlləri: açarlar enum dəyərləridir, dəyərlər — istənilən obyekt ola bilər.
- Sürətli giriş: HashMap<Enum, V>-dən daha sürətli və yığcamdır.
Nümunə: həftə günləri üzrə qiymətlər
EnumMap<Day, Integer> prices = new EnumMap<>(Day.class);
prices.put(Day.MON, 100);
prices.put(Day.SAT, 200);
System.out.println(prices.get(Day.SAT)); // 200
Nümunə: sonlu avtomat
enum State { START, RUNNING, STOPPED }
EnumMap<State, EnumSet<State>> transitions = new EnumMap<>(State.class);
transitions.put(State.START, EnumSet.of(State.RUNNING));
transitions.put(State.RUNNING, EnumSet.of(State.STOPPED));
transitions.put(State.STOPPED, EnumSet.noneOf(State.class));
3. Tələlər: enum-un dəyişdirilməsi və seriyalaşdırma
EnumSet və EnumMap sizin enum-unuzun dəyərlərinin tərkibindən və sırasından asılıdır. Yeni element əlavə etsəniz, köhnəni silsəniz və ya yerlərini dəyişsəniz, saxlanmış və ya seriyalaşdırılmış kolleksiyalar düzgün davranmaya bilər.
Seriyalaşdırma
- EnumSet və EnumMap seriyalaşdırıla bilir, lakin enum seriyalaşdırma ilə deserializasiya arasında dəyişərsə, xətalar/məlumat itkisi mümkündür.
- Seriyalaşdırmadan sonra enum-dan dəyərin silinməsi oxunuş zamanı istisnaya demək olar ki, zəmanətli şəkildə gətirəcək.
Ən yaxşı təcrübə:
- EnumSet/EnumMap-i seriyalaşdırmayın, əgər enum-un sabitliyinə əmin deyilsinizsə.
- Uzunmüddətli saxlama üçün, məsələn, dəyərlərin sətir təqdimatlarının siyahısından istifadə edin.
4. Faydalı nüanslar
EnumSet/EnumMap ilə adi kolleksiyaların müqayisəsi
| Kolleksiya | Açar/element | Daxili quruluş | Performans | Yaddaş | Null |
|---|---|---|---|---|---|
|
|
bit maskası | O(1) | çox az | olmaz |
|
|
hash cədvəli | O(1) | daha çox | olur |
|
|
ordinal üzrə massiv | O(1) | çox az | olmaz |
|
|
hash cədvəli | O(1) | daha çox | olur |
Ən yaxşı təcrübələr
- Dəyər dəstləri üçün EnumSet istifadə edin (of, noneOf, allOf, complementOf).
- Açarı — enum olan assosiativ cədvəllər üçün EnumMap istifadə edin.
- “Nəhəng” enumerasiyalardan qaçın — yüzlərlə dəyəri olan siyahılar yığcamlığı pisləşdirir.
- enum dəyişə biləcəksə, seriyalaşdırmayın.
- null-u açar və ya dəyər kimi istifadə etməyin.
5. Təcrübə: tətbiqdə EnumSet və EnumMap-dən necə istifadə etməli
Nümunə: istifadəçi rollarının saxlanması
enum Role { USER, ADMIN, MODERATOR }
class User {
private EnumSet<Role> roles = EnumSet.noneOf(Role.class);
public void addRole(Role role) {
roles.add(role);
}
public boolean isAdmin() {
return roles.contains(Role.ADMIN);
}
}
Nümunə: vəziyyət keçidlərinin cədvəli
enum State { NEW, IN_PROGRESS, DONE }
EnumMap<State, EnumSet<State>> transitions = new EnumMap<>(State.class);
transitions.put(State.NEW, EnumSet.of(State.IN_PROGRESS));
transitions.put(State.IN_PROGRESS, EnumSet.of(State.DONE));
transitions.put(State.DONE, EnumSet.noneOf(State.class));
6. EnumSet/EnumMap ilə işləyərkən tipik səhvlər
Səhv № 1: Enum olmayan tiplə EnumSet/EnumMap istifadə etmək.
Bu kolleksiyalar yalnız enum olan tiplərlə işləyir.
// EnumSet<String> set = EnumSet.of("A", "B"); // Tərtib xətası!
Səhv № 2: Çox böyük enum-lar üçün EnumSet/EnumMap istifadə etmək.
Yüzlərlə dəyəri olan enumerasiyalar yığcamlığı pisləşdirir. Bununla belə, bu, yaddaş baxımından eyni məlumatlar üçün HashSet/HashMap-dən çox vaxt yenə də daha yaxşıdır.
Səhv № 3: Seriyalaşdırmadan sonra enum-u dəyişmək.
Seriyalaşdırmadan sonra dəyərləri əlavə etmək/silmək/sırasını dəyişmək oxunuş zamanı xətalara və ya məlumat itkilərinə gətirib çıxarır.
Səhv № 4: EnumSet/EnumMap-i null ilə istifadə etmək.
Nə EnumSet-in elementləri, nə də EnumMap-in açarları/dəyərləri null ola bilər.
EnumSet<Day> days = EnumSet.of(null); // NullPointerException!
EnumMap<Day, String> map = new EnumMap<>(Day.class);
map.put(null, "test"); // NullPointerException!
Səhv № 5: EnumSet-in “adi” Set olmasını gözləmək.
EnumSet yalnız öz enum-unun dəyərlərini saxlayır; ora enumerasiya xaricindən istənilən obyekt əlavə edə bilməzsiniz.
Səhv № 6: “Dəyişən” enum-lar üçün EnumSet/EnumMap istifadə etmək.
Əgər enumerasiyalar rantaymda generasiya olunur və ya əvəzlənirsə (dinamik yükləmə/refleksiya), bu strukturlar düzgün işləməyəcək.
GO TO FULL VERSION