التحكّم في التدفّق والحلقات

جملة if / else if / else

15 دقيقة الدرس 2 من 14

جملة if / else if / else

كل برنامج يحتاج في مرحلة ما إلى اتخاذ قرار: نفّذ هذا الكود فقط إذا كان شيء ما صحيحًا، أو اختَر بين عدة مسارات بحسب قيمة معينة. جملة if في Java هي الأداة الأساسية لهذا النوع من التفريع. أنت تعرف بالفعل ما تُنتجه التعبيرات المنطقية (من الدرس السابق)؛ والآن ستتعلم كيف تتصرف بناءً عليها.

كتلة if الأساسية

تُقيّم جملة if تعبيرًا منطقيًا. عندما يكون التعبير true تنفّذ الكتلة؛ وعندما يكون false يتخطّاها Java تمامًا.

int temperature = 35; if (temperature > 30) { System.out.println("الجو حار في الخارج."); } // الناتج: الجو حار في الخارج.

تُعرّف الأقواس المعقوصة { } الكتلة — مجموعة الجمل التي تنتمي إلى هذا الفرع. يمكنك وضع أي عدد من الجمل بداخلها.

إضافة فرع else

يوفّر فرع else البديل — الكود الذي يُنفَّذ عندما يكون شرط if خاطئًا (false).

int temperature = 18; if (temperature > 30) { System.out.println("الجو حار في الخارج."); } else { System.out.println("الطقس مريح."); } // الناتج: الطقس مريح.

سيُنفَّذ واحد بالضبط من الفرعين — لا كلاهما معًا، ولا لا شيء منهما. هذا هو الضمان الذي يمنحك إياه تركيب if / else.

التسلسل مع else if

عندما تكون هناك أكثر من حالتين محتملتين، تُسلسل شروطًا إضافية باستخدام else if. تُقيّمها Java من الأعلى إلى الأسفل وتنفّذ أول فرع يكون شرطه true، ثم تتخطّى جميع ما بعده.

int score = 74; if (score >= 90) { System.out.println("التقدير: A"); } else if (score >= 80) { System.out.println("التقدير: B"); } else if (score >= 70) { System.out.println("التقدير: C"); } else if (score >= 60) { System.out.println("التقدير: D"); } else { System.out.println("التقدير: F"); } // الناتج: التقدير: C
الترتيب مهم. لأن Java تتوقف عند أول تطابق، اكتب الشرط الأكثر تقييدًا أولًا. لو وضعت score >= 60 في الأعلى، لطبعت درجة 95 التقدير "D" — وهذا خطأ واضح. فكّر دومًا في أضيق نطاق وضعه أولًا.

جمل if المتداخلة

يمكنك وضع جملة if داخل كتلة if أخرى. يُسمى هذا التداخل، وهو مفيد عندما لا تكون القرار الثاني منطقيًا إلا بعد حسم القرار الأول.

boolean hasTicket = true; int age = 17; if (hasTicket) { if (age >= 18) { System.out.println("تم السماح بالدخول."); } else { System.out.println("يجب أن يكون عمرك 18 عامًا أو أكثر."); } } else { System.out.println("يرجى شراء تذكرة أولًا."); } // الناتج: يجب أن يكون عمرك 18 عامًا أو أكثر.
أبقِ التداخل ضحلًا. إذا تجاوز مستويين فهذا مؤشر على أن المنطق ينبغي استخراجه في دالة مساعدة أو إعادة كتابته باستخدام المعاملات المنطقية (&&، ||) لدمج الشروط في جملة if واحدة. التداخل العميق يجعل الكود صعب القراءة وصعب الاختبار.

فخ else المعلَّق (Dangling-else)

انظر إلى هذا الكود الغامض:

int x = 5; if (x > 0) if (x > 10) System.out.println("أكبر من 10"); else System.out.println("ليس موجبًا"); // لأيّ if ينتمي هذا؟

يبدو المسافة البادئة وكأن else مقترن بـ if (x > 0) الخارجية، لكن قاعدة Java هي: دائمًا تنتمي else إلى أقرب if سابقة لا تمتلك else بعد. لذا تقترن else هنا بـ if (x > 10). بالنسبة لـ x = 5، الشرط الخارجي صحيح لكن الداخلي خاطئ، فتُنفَّذ else وتطبع "ليس موجبًا" — رغم أن 5 موجبة فعلًا. هذه هي خطأ else المعلَّق الكلاسيكي.

استخدم الأقواس المعقوصة دائمًا، حتى مع الجسم ذي السطر الواحد. الحل الآمن بسيط جدًا: ضع { } حول كل جسم. حينئذٍ لا يمكن للمسافة البادئة وتفسير المُترجم أن يختلفا.
if (x > 0) { if (x > 10) { System.out.println("أكبر من 10"); } } else { System.out.println("ليس موجبًا"); // ينتمي الآن بوضوح للـ if الخارجية }

فخ غياب الأقواس المعقوصة

فخ مشابه: حذف الأقواس ثم إضافة جملة ثانية لاحقًا إلى الجسم.

boolean isAdmin = false; // الكود الأصلي — يعمل بشكل صحيح if (isAdmin) System.out.println("مرحبًا أيها المدير."); // يضيف أحدهم سطرًا ثانيًا ناسيًا الأقواس if (isAdmin) System.out.println("مرحبًا أيها المدير."); System.out.println("جارٍ تحميل لوحة المدير..."); // تُنفَّذ دائمًا — ليست داخل if!

الـ println الثانية خارج الـ if تمامًا. لأنه لا توجد أقواس، فقط الجملة الأولى بعد if هي المشروطة. ستطبع "جارٍ تحميل لوحة المدير..." لكل مستخدم. هذا خطأ حقيقي وخفي يشبه ثغرات الأمان. الحل هو نفسه: استخدم الأقواس دائمًا.

تجميع كل شيء معًا

إليك مثالًا صغيرًا مكتفيًا بذاته يستخدم التفريع لوصف إشارة المرور:

String light = "yellow"; if (light.equals("green")) { System.out.println("سِر."); } else if (light.equals("yellow")) { System.out.println("أبطئ."); } else if (light.equals("red")) { System.out.println("قف."); } else { System.out.println("إشارة غير معروفة."); } // الناتج: أبطئ.
استخدم .equals() لمقارنة النصوص، وليس ==. يتحقق المعامل == من أن متغيرين يشيران إلى نفس الكائن في الذاكرة، وليس من تساوي محتواهما. لمقارنة محتوى النصوص استخدم دائمًا .equals() أو .equalsIgnoreCase().

الخلاصة

  • تُنفَّذ كتلة if فقط عندما يكون شرطها true.
  • يوفّر else المسار البديل عندما لا يكون أي شرط سابق true.
  • يُسلسل else if شروطًا إضافية؛ وتختار Java أول تطابق وتتجاهل الباقي.
  • تُقيَّم الشروط من الأعلى إلى الأسفل — ضع الفحص الأكثر تحديدًا أولًا.
  • التداخل مسموح به لكن يجب إبقاؤه ضحلًا؛ يُفضَّل استخدام المعاملات المنطقية لدمج الشروط عند الإمكان.
  • ضع دائمًا الأقواس المعقوصة حول أجسام if وelse if وelse لتجنّب فخّي else المعلَّق وغياب الأقواس.