0Pricing
Java Academy · درس

EnumSet وEnumMap

استخدم EnumSet وEnumMap لإنشاء مجموعات فعّالة وآمنة من ناحية الأنواع تعتمد على enum

EnumSet وEnumMap درس مجاني في Java Academy على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Java Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Java Academy 4 دروس في المجموع.

EnumSet و EnumMap

إن EnumSet وEnumMap تطبيقان محسّنان بدرجة كبيرة لمجموعات البيانات الخاصة بـ enum. وهما يستخدمان متجهات بتات داخليًا، ولذلك فهما أسرع بكثير من HashSet وHashMap عند استخدام مفاتيح enum.

EnumSet: إنشاء المجموعات

يوفّر EnumSet دوال مصنع لإنشاء مجموعات من ثوابت enum.

import java.util.*;

enum Day { MON, TUE, WED, THU, FRI, SAT, SUN }

EnumSet<Day> weekdays  = EnumSet.range(Day.MON, Day.FRI);
EnumSet<Day> weekend   = EnumSet.of(Day.SAT, Day.SUN);
EnumSet<Day> allDays   = EnumSet.allOf(Day.class);
EnumSet<Day> noDays    = EnumSet.noneOf(Day.class);

System.out.println(weekdays); // [MON, TUE, WED, THU, FRI]
System.out.println(weekend);  // [SAT, SUN]
System.out.println(allDays.size()); // 7

EnumSet: عمليات المجموعات

يدعم EnumSet عمليات المجموعات القياسية، مثل الاتحاد والتقاطع والمتممة. وتتميز هذه العمليات بسرعة كبيرة جدًا بفضل تطبيق متجه البتات.

import java.util.*;

enum Permission { READ, WRITE, DELETE, ADMIN, EXPORT }

EnumSet<Permission> userPerms  = EnumSet.of(Permission.READ, Permission.WRITE);
EnumSet<Permission> adminPerms = EnumSet.allOf(Permission.class);

// Complement
EnumSet<Permission> missing = EnumSet.complementOf(userPerms);
System.out.println("Missing: " + missing);
// Missing: [DELETE, ADMIN, EXPORT]

// Intersection (retain)
EnumSet<Permission> shared = EnumSet.copyOf(userPerms);
shared.retainAll(adminPerms);
System.out.println("Shared: " + shared); // [READ, WRITE]

EnumMap: ربط enum بالقيم

يستخدم EnumMap الترتيب العددي لـ enum كفهرس لمصفوفة داخليًا، ما يوفّر بحثًا بزمن O(1) أسرع من HashMap.

import java.util.*;

enum Quarter { Q1, Q2, Q3, Q4 }

EnumMap<Quarter, Double> revenue = new EnumMap<>(Quarter.class);
revenue.put(Quarter.Q1, 125_000.0);
revenue.put(Quarter.Q2, 148_500.0);
revenue.put(Quarter.Q3, 132_750.0);
revenue.put(Quarter.Q4, 175_200.0);

double total = revenue.values().stream()
    .mapToDouble(Double::doubleValue).sum();
System.out.printf("Annual revenue: $%.0f%n", total);
// Annual revenue: $581450

EnumMap: التكرار بالترتيب

يكرّر EnumMap المفاتيح دائمًا وفق ترتيب التصريح بثوابت enum، وليس وفق ترتيب الإدراج أو ترتيب التجزئة.

import java.util.*;

enum Month { JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC }

EnumMap<Month, Integer> salesUnits = new EnumMap<>(Month.class);
salesUnits.put(Month.MAR, 1420);
salesUnits.put(Month.JAN, 980);
salesUnits.put(Month.FEB, 1105);

// Iterates JAN, FEB, MAR (declaration order, not insertion order)
for (var entry : salesUnits.entrySet()) {
    System.out.println(entry.getKey() + ": " + entry.getValue());
}
// JAN: 980
// FEB: 1105
// MAR: 1420

نظام صلاحيات باستخدام EnumSet

نظام صلاحيات قائم على الأدوار، يستخدم EnumSet لإجراء عمليات التحقق من الصلاحيات بكفاءة وتصميم واجهة برمجية نظيف.

import java.util.*;

enum Permission { READ, WRITE, DELETE, PUBLISH, ADMIN }

record Role(String name, EnumSet<Permission> permissions) {
    boolean can(Permission p) { return permissions.contains(p); }
}

Role editor = new Role("Editor",
    EnumSet.of(Permission.READ, Permission.WRITE, Permission.PUBLISH));
Role viewer = new Role("Viewer",
    EnumSet.of(Permission.READ));

System.out.println(editor.can(Permission.WRITE));  // true
System.out.println(viewer.can(Permission.DELETE)); // false

مفاتيح الميزات باستخدام EnumMap

يُعد EnumMap مناسبًا جدًا لأنظمة مفاتيح الميزات، إذ يوفّر بحثًا سريعًا بزمن O(1) باستخدام مفاتيح enum.

import java.util.*;

enum Feature { DARK_MODE, BETA_EDITOR, AI_SUGGESTIONS, EXPORT_PDF }

class FeatureFlags {
    private final EnumMap<Feature, Boolean> flags = new EnumMap<>(Feature.class);

    public FeatureFlags() {
        for (Feature f : Feature.values()) flags.put(f, false);
    }

    public void enable(Feature f)  { flags.put(f, true); }
    public void disable(Feature f) { flags.put(f, false); }
    public boolean isEnabled(Feature f) { return flags.getOrDefault(f, false); }
}

FeatureFlags ff = new FeatureFlags();
ff.enable(Feature.DARK_MODE);
System.out.println(ff.isEnabled(Feature.DARK_MODE));      // true
System.out.println(ff.isEnabled(Feature.AI_SUGGESTIONS)); // false

الأداء: EnumSet مقارنةً بـ HashSet

يستخدم EnumSet قناع بتات long واحدًا للتعدادات التي تحتوي على 64 ثابتًا أو أقل، ولذلك تكون عملياته عمليات بتات بزمن O(1). أما HashSet فيستخدم حاويات تجزئة، ما يجعله أبطأ ويتطلب مقدارًا أكبر من الموارد.

import java.util.*;

enum Day { MON, TUE, WED, THU, FRI, SAT, SUN }

// EnumSet: bit operations on a long value
EnumSet<Day> workDays = EnumSet.range(Day.MON, Day.FRI);

// HashSet: hash table with boxing overhead
Set<Day> hashWorkDays = new HashSet<>(Arrays.asList(
    Day.MON, Day.TUE, Day.WED, Day.THU, Day.FRI));

// Both work, but EnumSet is ~5x faster for contains/add/remove
// and uses less memory
System.out.println(workDays.contains(Day.SAT));     // false
System.out.println(workDays.contains(Day.MON));     // true

‏getOrDefault و computeIfAbsent في EnumMap

يدعم EnumMap جميع عمليات Map، بما في ذلك getOrDefault وcomputeIfAbsent وmerge.

import java.util.*;

enum Category { FOOD, ELECTRONICS, CLOTHING, BOOKS }

EnumMap<Category, List<String>> catalog = new EnumMap<>(Category.class);

// computeIfAbsent creates the list on first use
catalog.computeIfAbsent(Category.BOOKS, k -> new ArrayList<>()).add("Clean Code");
catalog.computeIfAbsent(Category.BOOKS, k -> new ArrayList<>()).add("Effective Java");
catalog.computeIfAbsent(Category.ELECTRONICS, k -> new ArrayList<>()).add("Laptop");

System.out.println(catalog.get(Category.BOOKS));
// [Clean Code, Effective Java]
System.out.println(catalog.getOrDefault(Category.FOOD, List.of()));
// []

نمط Multimap باستخدام EnumMap

يمكن دمج EnumMap مع قيم من نوع List لإنشاء multimap بمفاتيح enum، ما يتيح تجميع العناصر بكفاءة حسب الفئة.

import java.util.*;
import java.util.stream.*;

enum Priority { LOW, NORMAL, HIGH, URGENT }
record Task(String name, Priority priority) {}

List<Task> tasks = List.of(
    new Task("Fix login bug", Priority.URGENT),
    new Task("Update docs",   Priority.LOW),
    new Task("Add unit tests",Priority.NORMAL),
    new Task("Deploy hotfix", Priority.URGENT)
);

// Group by priority into EnumMap
EnumMap<Priority, List<Task>> byPriority = tasks.stream()
    .collect(Collectors.groupingBy(Task::priority,
        () -> new EnumMap<>(Priority.class),
        Collectors.toList()));

byPriority.forEach((p, ts) ->
    System.out.println(p + ": " + ts.stream().map(Task::name).collect(Collectors.joining(", "))));

متى يُستخدم EnumSet أو EnumMap

فيما يلي ملخص لاختيار كل منهما:

  • EnumSet: عند الحاجة إلى مجموعة من قيم enum، مثل الصلاحيات والميزات النشطة والأيام المحددة
  • EnumMap: عند ربط كل ثابت من enum بقيمة، مثل إعدادات كل ميزة والنتيجة لكل مستوى والعناصر لكل فئة
  • كلاهما: يُفضّل استخدامهما بدلًا من HashSet وHashMap مع مفاتيح enum، لأنهما أسرع ويستهلكان ذاكرة أقل ويحافظان على الترتيب

اختبار سريع

ما بنية البيانات الداخلية التي يستخدمها EnumSet مع التعدادات التي تحتوي على 64 ثابتًا أو أقل؟

مراجعة: EnumSet وEnumMap

أهم النقاط:

  • يستخدم EnumSet متجه بتات، ما يجعله سريعًا جدًا مع مجموعات enum الصغيرة
  • تُعد EnumSet.of() وrange() وallOf() وnoneOf() من دوال المصنع الشائعة
  • يستخدم EnumMap مصفوفات مفهرسة بالترتيب العددي، ما يوفّر بحثًا بزمن O(1) مرتّبًا وفق ترتيب التصريح
  • استخدموا EnumSet لمجموعات الصلاحيات ومفاتيح الميزات وتصفية أيام الأسبوع
  • استخدموا EnumMap لإعدادات كل فئة وجداول النتائج وربط الميزات بالقيم
  • يحافظ كلاهما على ترتيب التصريح بثوابت enum، وهما أكثر كفاءة من المجموعات المعتمدة على التجزئة

الأسئلة الشائعة

هل درس «EnumSet وEnumMap» مجاني؟

نعم — نص درس «EnumSet وEnumMap» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Java Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Java Academy 4 دروس في المجموع.

ماذا ستتعلم في «EnumSet وEnumMap»؟

استخدم EnumSet وEnumMap لإنشاء مجموعات فعّالة وآمنة من ناحية الأنواع تعتمد على enum تتمرن على Java Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Java Academy؟

لا تُشترط خبرة سابقة. Java Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.

كم من الوقت يستغرق درس «EnumSet وEnumMap»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Java Academy هذا؟

نعم. كل درس في Java Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. تعريف التعدادات واستخدامها
  2. التعدادات ذات الحقول والأساليب
  3. تعبيرات switch مع التعدادات
  4. EnumSet وEnumMap
← العودة إلى Java Academy