النوع enum في جافا | Java enum

مفهوم النوع enum في جافا

enum هي كلمة محجوزة في جافا, تستخدم لتعريف عدة ثوابت ضمن مجموعة واحدة بشكل منطقي.
و في النهاية تعتبر هذه المجموعة كنوع جديد من البيانات و فيها عدة قيم محتملة.

النوع enum مفيد جداً في حال أردت بناء كود مخصص فقط للتعامل مع نوع محدد من القيم و في حال حاول أي مبرمج آخر عدم الإلتزام بنوع البيانات الذي فرضته أنت و قام بتمرير قيم من نوع آخر فإنه يتم تنبيهه مباشرةً قبل تشغيل الكود و في حال أصر على ذلك و قام بتشغيل الكود فإن مترجم لغة جافا سيمنعه وقت التشغيل و يظهر له خطأ.

بشكل عام, في حال أردت تعريف مجموعة قيم مترابطة يستحيل أن تتبدل فالخيار الأمثل هو تعريف هذه القيم في الأساس بداخل enum.

أمثلة حول بعض المعلومات الثابتة في الحياة و التي أيضاً تعتبر ثابتة في المنطق هي:

  • فصول السنة ( الخريف, الشتاء, الربيع, الصيف )

  • الإتجاهات ( الشمال - الجنوب - الشرق - الغرب )

  • أيام الأسبوع ( الإثنين - الثلاثاء - الأربعاء إلخ.. )

  • أشهر السنة ( كانون الثاني - شباط - آذار إلخ.. )

  • الجنس ( ذكر - أنثى )

عند التعامل مع هذا النوع الثابت من البيانات و الذي لا نريد لأحد أن يعبث به فإننا نستخدم النوع enum و هذا ما سنراه لاحقاً في الأمثلة.


مصطلحات تقنية النوع enum

الـ enum يقال له تعداد في اللغة العربية حيث نضع فيه مجموعة عناصر.

التعامل مع النوع enum في جافا

التعامل مع الـ enum يشبه كثيراً التعامل مع الكلاس المعرف كـ final static حيث لا يمكن إنشاء كائنات منه و يمكن الوصول بشكل مباشر للثوابت الموضوعة فيه.


نقاط مهمة حول النوع enum

  • يزيد أمان أنواع البيانات التي سيتم التعامل معها.

  • يمكن إستخدامه في الجملة switch.

  • يمكن تعريفه ضمن ملف خاص مثل الكلاس و يمكن تعريفه ضمن كلاس.

  • كل ثابت فيه, عبارة عن كائن من نفس نوعه و يعتبر نوعه public final static.

  • يمكنه أن يحتوي على متغيرات, دوال, كونستركتورات.

  • لا يمكن إنشاء كائنات منه و لا داعي لذلك أصلاً لأنه يمكن الوصول لثوابته بشكل مباشر.

  • عند تعريف كونستركتور فيه فإنه يجب تعريفه كـ private لأنه لا يمكن إنشاء كائنات منه و هذا أمر منطقي.

  • يمكنه أن يفعل implements لإنترفيس أو أكثر.

  • لا يمكنه أن يرث من أي كلاس لأنه في الواقع يرث من كلاس إسمه Enum.

  • يمكنك إستدعاء الدالة values() من أي enum للحصول على مصفوفة من نفس نوعه و فيها نسخة من كل قيمه.



معلومة تقنية النوع enum

كل ثابت تضعه في الـ enum يتم إعطاؤه رقم Index ابتداءاً من الرقم 0 يشير لموقعه فيه مثل المصفوفة.
فمثلاً العنصر الأول يعطى Index رقم 0 و العنصر الثاني يعطى Index رقم 1 و هكذا.

يمكنك معرفة رقم الـ Index المعطى لأي ثابت في الـ enum بواسطة الدالة ordinal() و لكنك على الأغلب لن تحتاج إلى ذلك.

أمثلة شاملة حول النوع enum في جافا


كيف تقوم بتعريف enum بداخل كلاس  

ستتعلم من المثال التالي كيف تقوم بتعريف enum بداخل كلاس بالإضافة إلى معرفة كيف يمكن الوصول للثوابت الموجودة فيه و معرفة Index الثابت.



في المثال التالي قمنا بتعريف كلاس عادي و بداخله قمنا بتعريف enum يمثل أيام الأسبوع إسمه Days.
في الدالة main() قمنا بعرض قيمة أول ثابت موجود في الـ enum بالإضافة إلى رقم الـ Index الخاص فيه.

مثال

Main.java
                    public class Main {

                    // وضعنا فيه 7 ثوابت Days إسمه enum هنا قمنا بتعريف
                    enum Days {
                    MONDAY,
                    TUESDAY,
                    WEDNESDAY,
                    THURSDAY,
                    FRIDAY,
                    SATURDAY,
                    SUNDAY
                    }

                    public static void main(String[] args) {

                    // Days الموجود في التعداد MONDAY هنا قمنا بطباعة إسم الثابت
                    System.out.println(Days.MONDAY);

                    // Days بالنسبة للتعداد MONDAY الثابت index هنا قمنا بطباعة رقم
                    System.out.println(Days.MONDAY.ordinal());

                    }

                    }
                  

سنحصل على النتيجة التالية عند التشغيل.

MONDAY
0

 كيف تقوم بعرض جميع الثوابت الموجودة في الـ enum 

ستتعلم من المثال التالي كيف تقوم بعرض جميع الثوابت الموجودة في الـ enum بالإعتماد على الدالة values() و الحلقة for each.



في المثال التالي قمنا بتعريف enum يمثل أيام الأسبوع إسمه Days.
في الدالة main() قمنا باستخدام الدالة values() و التي ترجع مصفوفة فيها جميع عناصر التعداد Days. عناصر هذه المصفوفة قمنا بعرضها مباشرة باستخدام حلقة For Each.

مثال

Main.java
                    public class Main {

                    // وضعنا فيه 7 ثوابت Days إسمه enum هنا قمنا بتعريف
                    enum Days {
                    MONDAY,
                    TUESDAY,
                    WEDNESDAY,
                    THURSDAY,
                    FRIDAY,
                    SATURDAY,
                    SUNDAY
                    }

                    public static void main(String[] args) {

                    // و ستعرض كل عنصر فيها values() هذه الحلقة ستقوم بالمرور على جميع العناصر التي سترجعها الدالة
                    for(Days d: Days.values())
                    {
                    System.out.println(d);
                    }

                    }

                    }
                  

سنحصل على النتيجة التالية عند التشغيل.

MONDAY
TUESDAY
WEDNESDAY
THURSDAY
FRIDAY
SATURDAY
SUNDAY

طريقة تخزين ثابت موجود في enum بداخل كائن من نفس نوعه

ستتعلم من المثال التالي كيف تقوم بتخزين ثابت موجود في enum بداخل كائن من نفس نوعه.



في المثال التالي قمنا بتعريف enum يمثل أيام الأسبوع إسمه Days.
في الدالة main() قمنا بتعريف كائن نوعه Days و إسمه day وضعنا فيه نسخة من رابع ثابت موجود في الـ Days.

مثال

Main.java
                    public class Main {

                    // وضعنا فيه 7 ثوابت Days إسمه enum هنا قمنا بتعريف
                    enum Days {
                    MONDAY,
                    TUESDAY,
                    WEDNESDAY,
                    THURSDAY,
                    FRIDAY,
                    SATURDAY,
                    SUNDAY
                    }

                    public static void main(String[] args) {

                    // THURSDAY قيمته تساوي قيمة الثابت Days و نوعه day هنا قمنا بتعريف كائن إسمه
                    Days day = Days.THURSDAY;

                    System.out.println(day);

                    }

                    }
                  

سنحصل على النتيجة التالية عند التشغيل.

THURSDAY

 كيف تقوم بتحديد قيمة كل ثابت في الـ enum

ستتعلم من المثال التالي كيف تقوم بتحديد قيمة كل ثابت في الـ enum.



في المثال التالي قمنا بتعريف enum إسمه Size, وضعنا فيه 4 ثوابت مع وضع قيمة عددية لكل ثابت.
في الدالة main() قمنا بعرض كل ثابت و بجانبه القيمة التي يمثلها.

مثال

Main.java
                    public class Main {

                    // وضعنا فيه 4 ثوابت مع تحديد قيمهم Size إسمه enum هنا قمنا بتعريف
                    enum Size {

                    // هنا قمنا بتعريف أسماء الثوابت و تحديد قيمهم
                    SMALL(100),
                    MEDIUM(150),
                    LARGE(200),
                    XLARGE(250);

                    // هنا قمنا بتعريف المتغير الذي سيتم إستخدامه بشكل تلقائي لتخزين قيمة كل ثابت تم تعريفه
                    private int value;

                    // هنا قمنا بتعريف الكونستركتور الذي سيقوم بربط إسم كل ثابت بالقيمة التي تم وضعها بجانبه
                    private Size(int value){
                    this.value = value;
                    }

                    }

                    public static void main(String[] args) {

                    // و ستعرض إسم و قيمة كل عنصر فيها values() هذه الحلقة ستقوم بالمرور على جميع العناصر التي سترجعها الدالة
                    for(Size s: Size.values())
                    {
                    System.out.println(s + " " + s.value);
                    }

                    }

                    }
                  

سنحصل على النتيجة التالية عند التشغيل.

SMALL 100
MEDIUM 150
LARGE 200
XLARGE 250

 كيف تضع أكثر من قيمة لكل ثابت في الـ enum

ستتعلم من المثال التالي كيف تضع أكثر من قيمة لكل ثابت في الـ enum.



في المثال التالي قمنا بتعريف enum إسمه Size, وضعنا فيه 4 ثوابت مع وضع قيمة عددية و قيمة نصية لكل ثابت إسم.
في الدالة main() قمنا بعرض القيمة النصية و القيمة العددية لكل ثابت.

مثال

Main.java
                    public class Main {

                    // وضعنا فيه 4 ثوابت مع تحديد قيمهم Size إسمه enum هنا قمنا بتعريف
                    enum Size {

                    // هنا قمنا بتعريف الثوابت مع إعطاء كل واحد منهم رقم يمثل قيمة الثابت و نص يمثل إسم الثابت
                    SMALL(100, "small"),
                    MEDIUM(150, "meduim"),
                    LARGE(200, "large"),
                    XLARGE(250, "x-large");

                    // هنا قمنا بتعريف المتغيرين اللذي سيتم إستخدامهما بشكل تلقائي لتخزين إسم و قيمة كل ثابت تم تعريفه
                    private int value;
                    private String name;

                    // هنا قمنا بتعريف الكونستركتور الذي سيقوم بربط كل ثابت بالإسم و القيمة التي تم وضعها بجانبه
                    private Size(int value, String name){
                    this.value = value;
                    this.name = name;
                    }

                    }

                    public static void main(String[] args) {

                    // لكل عنصر فيها value و الـ name و ستعرض قيمة الـ values() هذه الحلقة ستقوم بالمرور على جميع العناصر التي سترجعها الدالة
                    for(Size s: Size.values())
                    {
                    System.out.println(s.name + " " + s.value);
                    }
                    }

                    }
                  

سنحصل على النتيجة التالية عند التشغيل.

small 100
meduim 150
large 200
x-large 250

 كيف تعرف قيمة الثابت الذي إختاره المستخدم 

ستتعلم من المثال التالي كيف تعرف قيمة الثابت الذي إختاره المستخدم من الـ enum بواسطة الجملة switch.



في المثال التالي قمنا بتعريف enum يمثل أيام الأسبوع إسمه Days.
في الدالة main() قمنا بتعريف كائن نوعه Days و إسمه userSelectedDay وضعنا فيه نسخة من رابع ثابت موجود في الـ Days و اعتبرنا أن المستخدم هو من قام باختيار قيمة هذا الثابت. بعدها قمنا بمقارنة الثابت userSelectedDay مع جميع الثوابت الموجودة في التعداد Days بواسطة الجملة switch.

مثال

Main.java
                    public class Main {

                    // وضعنا فيه 7 ثوابت Days إسمه enum هنا قمنا بتعريف
                    enum Days {
                    MONDAY,
                    TUESDAY,
                    WEDNESDAY,
                    THURSDAY,
                    FRIDAY,
                    SATURDAY,
                    SUNDAY
                    }

                    public static void main(String[] args) {

                    // THURSDAY قيمته تساوي قيمة الثابت Days و نوعه userSelectedDay هنا قمنا بتعريف كائن إسمه
                    Days userSelectedDay = Days.THURSDAY;

                    // userSelectedDay هنا قمنا باختبار نوع الثابت
                    switch (userSelectedDay)
                    {
                    // سيتم تنفيذ أمر الطباعة التالي THURSDAY أو WEDNESDAY أو TUESDAY أو MONDAY إذا كان يمثل نسخة من الثابت
                    case MONDAY:
                    case TUESDAY:
                    case WEDNESDAY:
                    case THURSDAY:
                    System.out.println("We are available from 8:00 AM to 4:00 PM.");
                    break;

                    // سيتم تنفيذ أمر الطباعة التالي FRIDAY إذا كان يمثل نسخة من الثابت
                    case FRIDAY:
                    System.out.println("We are available from 8:00 AM to 12:00 PM.");
                    break;

                    // إذا كان لا يمثل نسخة من الثوابت المذكورة سابقاً سيتم تنفيذ أمر الطباعة التالي
                    default:
                    System.out.println("We are not available on vacations.");
                    }

                    }

                    }
                  

سنحصل على النتيجة التالية عند التشغيل.

We are available from 8:00 AM to 4:00 PM.

 كيف تقوم بتعريف enum في ملف خاص بطريقتين

ستتعلم من المثال التالي كيف تقوم بتعريف enum في ملف خاص بطريقتين.
فعلياً, ستتعلم كيف تستطيع إنشاء كلاس عادي و من ثم تحويله لـ enum. و ستتعلم كيف تستطيع إنشاء enum مباشرةً في برنامج NetBeans.



أسهل طريقة لتعريف enum في ملف خاص

في البداية, تذكر أنه يمكنك تعريف enum بداخل كلاس أو في ملف خارجي كما سبق و شرحنا في الدرس.

الآن لتعريف enum في ملف خاص, يمكنك إنشاء كلاس جافا عادي, و من ثم قم فقط بتبديل كلمة class بكلمة enum.


مثال

هنا قمنا بإنشاء كلاس إسمه Days.

                  public class Days {
                  // class عبارة عن Days هنا
                  }
                

بعد إنشاء الكلاس, قم بتبديل كلمة class بكلمة enum فقط كالتالي.

                  public enum Days {
                  // enum عبارة عن Days هنا
                  }
                

 أهمية الـ enum في حماية الكود

ستتعلم من المثال التالي أهمية الـ enum في حماية الكود خاصةً إذا كنت تعمل ضمن فريق و تريد أن يلتزم زملاؤك بالأنواع التي يمكن إستخدامها.

شاهد المثال »

في البداية, أسلوب كتابة الكود الذي ستتعلمه من المثال التالي ستتعامل معه كثيراً عند بناء تطبيقات فيها واجهة مستخدم و عند التعامل مع قواعد البيانات حيث ستتعامل مع دوال كثيرة يمكنك تمرير أنواع محددة من القيم لها.


الآن لنفترض أننا أردنا بناء لعبة يستطيع اللاعب أن يلعبها بثلاث مستويات كالتالي:

  • مستوى سهل ( Easy).

  • مستوى متوسط ( Normal).

  • مستوى صعب ( Hard).

الآن لكتابة كود هذه اللعبة و الذي قد يتألف من آلاف الأسطر البرمجية و التي ستكون موزعة على عدة ملفات جافا بدون القلق من مسألة كيف سيعرف كل مبرمج في الفريق كيف سيتم تحديد مستوى الصعوبة في اللعبة و لضمان أن تعرفوا جميعكم المستويات المتوفرة فيها و لتعلموا بنفس المنطق, فإنه من الأفضل أن يتم تعريف enum واحد إسمه Level و بداخله ثلاث ثوابت إسمها EASY و NORMAL و HARD.
و عندها سيقوم كل مبرمج بكتابة الكود بناءاً على قيمة هذه الثوابت كما فعلنا في المثال التالي.

مثال

هذا الملف مسؤول عنه مبرمج واحد و هو لتحديد المستويات المتوفرة في اللعبة.

Level.java
                    // وضعنا فيه 3 ثوابت Level إسمه enum هنا قمنا بتعريف
                    public enum Level {
                    EASY,
                    NORMAL,
                    HARD
                    }
                  

هذا الملف مسؤول عنه مبرمج واحد و يكتب فيه الرسائل التي يمكن أن تظهر في اللعبة على أساس مستوى اللعبة.

Messages.java
                    public class Messages {

                    // لها لتحديد الرسالة التي سيتم إظهارها للمستخدم Level عند إستدعاء هذه الدالة يجب تمرير إحدى ثوابت الكلاس
                    // لها فإنها ستظهر خطأ أمام المبرمج الذي قام باستدعائها مباشرةً أثناء كتباة الكود Level إذا لم يتم تمرير إحدى ثوابت الـ
                    public void showPlayMessage(Level userLevel) {
                    switch (userLevel)
                    {
                    case EASY:
                    System.out.println("Play Game In Easy Mode");
                    break;
                    case NORMAL:
                    System.out.println("Play Game In normal Mode");
                    break;
                    case HARD:
                    System.out.println("Play Game In Hard Mode");
                    break;
                    }
                    }

                    }
                  

هذا الملف مسؤول عنه مبرمج واحد و هو ما سيشغل اللعبة.

Main.java
                    public class Main {

                    public static void main(String[] args) {

                    // لتطبع رسالة على أساسه Level.EASY مع تمرير الثابت showPlayMessage() و استدعاء الدالة Messages هنا قمنا بإنشاء كائن من الكلاس
                    Messages msg = new Messages();
                    msg.showPlayMessage(Level.EASY);

                    }

                    }
                  

سنحصل على النتيجة التالية عند التشغيل.

Play Game In Easy Mode