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

حلقة for

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

حلقة for

تُعدّ حلقة for أدقّ أدوات التكرار في Java. حين تعرف — أو تستطيع حساب — عدد التكرارات بالضبط، تمنحك for كامل التحكّم في سطر واحد مدمج: من أين تبدأ، ومتى تتوقّف، وكيف تتقدّم.

تشريح حلقة for

يضمّ التركيب النحوي ثلاثة أجزاء مستقلة في رأس الحلقة، مفصولة بفاصلة منقوطة:

for (initializer; condition; update) { // الجسم — يعمل طالما الشرط صحيح }
  • المُهيّئ (Initializer) — يُنفَّذ مرّة واحدة قبل بدء الحلقة. يُعرَّف فيه عادةً متغيّر عدّاد ويُهيَّأ.
  • الشرط (Condition) — يُقيَّم قبل كل تكرار. إن كان false توقّفت الحلقة فورًا.
  • التحديث (Update) — يُنفَّذ بعد كل تكرار لجسم الحلقة. يزيد العدّاد أو ينقصه عادةً.
ترتيب التنفيذ: المُهيّئ ← فحص الشرط ← الجسم ← التحديث ← فحص الشرط ← الجسم ← التحديث ← … ← الشرط خطأ ← انتهاء الحلقة.

العدّ تصاعديًا

النمط الأكثر شيوعًا هو العدّ من قيمة ابتدائية حتى حدٍّ معيّن (غير مشمول):

for (int i = 0; i < 5; i++) { System.out.println("i = " + i); } // الخرج: // i = 0 // i = 1 // i = 2 // i = 3 // i = 4

استخدام < بدلًا من <= هو الأسلوب المعتاد عند التعامل مع الفهارس التي تبدأ من الصفر (المصفوفات والقوائم)، لأنّ الفهارس الصالحة لمصفوفة طولها 5 هي بالضبط من 0 حتى 4.

int[] scores = {88, 72, 95, 60, 84}; for (int i = 0; i < scores.length; i++) { System.out.println("Score " + i + ": " + scores[i]); }

العدّ تنازليًا

عكس الاتجاه يعني فقط البدء من قيمة عالية، والفحص بـ >، وتناقص العدّاد:

for (int i = 5; i >= 1; i--) { System.out.println(i + "..."); } System.out.println("Go!"); // الخرج: // 5... // 4... // 3... // 2... // 1... // Go!
الحدود المشمولة وغير المشمولة: يستخدم العدّ التصاعدي عادةً < (حدّ علوي غير مشمول)، بينما يستخدم العدّ التنازلي عادةً >= (حدّ سفلي مشمول). الالتزام بهذه الاصطلاحات يمنع أخطاء الإزاحة بمقدار واحد.

خطوات مخصّصة

تعبير التحديث لا يقتصر على i++ أو i--. يمكنك استخدام أي تعبير صالح، بما في ذلك الجمع أو الطرح بخطوة أكبر:

// طباعة الأعداد الزوجية من 0 حتى 10 for (int i = 0; i <= 10; i += 2) { System.out.print(i + " "); } // الخرج: 0 2 4 6 8 10 System.out.println(); // العدّ تنازليًا بخطوة 3 for (int i = 15; i >= 0; i -= 3) { System.out.print(i + " "); } // الخرج: 15 12 9 6 3 0

يمكنك أيضًا الضرب أو القسمة للتقدّم بشكل أسّي:

// قوى العدد 2 حتى 1024 for (int n = 1; n <= 1024; n *= 2) { System.out.print(n + " "); } // الخرج: 1 2 4 8 16 32 64 128 256 512 1024

نطاق متغيّر الحلقة

حين تُعرِّف متغيّرًا داخل المُهيّئ (مثل int i = 0)، يوجد هذا المتغيّر داخل الحلقة فحسب. محاولة استخدامه بعد القوس الختامي تُسبّب خطأ في وقت التصريف:

for (int i = 0; i < 3; i++) { System.out.println(i); // صحيح } // System.out.println(i); // خطأ في التصريف — i خارج النطاق هنا

هذا مقصود ومفيد: تضييق نطاق العدّاد داخل الحلقة يمنع إعادة استخدامه عن طريق الخطأ وتعارض الأسماء. إن كنت تحتاج القيمة النهائية بعد الحلقة فعلًا، أعلن المتغيّر قبل الحلقة:

int i; for (i = 0; i < 10; i++) { // الجسم } System.out.println("انتهت الحلقة عند i = " + i); // 10 — متاح هنا
خطر الحلقة اللانهائية: إن لم يصبح الشرط false قطّ، تعمل الحلقة إلى الأبد. خطأ شائع هو تعبير تحديث يبتعد عن الحدّ:

for (int i = 0; i < 5; i--) { ... } — يصبح i سالبًا ولا يصل أبدًا إلى 5. تحقّق دائمًا من أن التحديث يحرّك العدّاد نحو شرط الخروج.

متغيّرات متعدّدة في رأس الحلقة

تسمح Java بتعديدات متعدّدة وتعبيرات تحديث متعدّدة، مفصولة بفواصل. يُفيد هذا أحيانًا حين يحتاج فهرسان للتحرّك معًا:

for (int lo = 0, hi = 4; lo < hi; lo++, hi--) { System.out.println("lo=" + lo + " hi=" + hi); } // الخرج: // lo=0 hi=4 // lo=1 hi=3 // lo=2 hi=2 (يفشل الشرط هنا وتنتهي الحلقة)
الحفاظ على قابلية القراءة: استخدام أكثر من متغيّرين في رأس for الواحدة يصبح صعب الفهم بسرعة. إن وجدت نفسك تحتاج ثلاثة عدّادات أو أكثر، فحلقة while مع توزيع المنطق داخل جسمها تكون عادةً أوضح.

الخلاصة

تجمع حلقة for التهيئة والشرط والتحديث في رأس واحد مقروء. استخدمها للعدّ تصاعديًا أو تنازليًا بأي خطوة. تذكّر أن المتغيّر المُعلَن في المُهيّئ نطاقه مقتصر على الحلقة — استخدمه بحرية بداخلها، وأعلنه خارجها إن احتجت القيمة النهائية بعد انتهاء الحلقة. في الدرس التالي نستكشف حلقة for-each المحسّنة، التي تتخلّى عن هذا التحكّم الدقيق مقابل تركيب أنظف عند التكرار على المجموعات.