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

break وcontinue والحلقات المسمّاة

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

break وcontinue والحلقات المسمّاة

حتى الآن كتبتَ حلقاتٍ تعمل من البداية حتى النهاية وفق شرطها الخاص. لكنّ البرامج الحقيقية غالبًا ما تحتاج إلى قطع الحلقة مبكرًا أو تخطّي دورة واحدة منها. يمنحك Java كلمتَين مفتاحيتَين لذلك — break وcontinue — بالإضافة إلى آلية التسمية التي تُوسّع كلتيهما للعمل عبر الحلقات المتداخلة.

break — الخروج من الحلقة مبكرًا

حين ينفّذ Java الأمر break، يخرج فورًا من أعمق حلقة (أو switch) محيطة به، ثم يكمل من أوّل سطر بعدها. هذا مفيد حين تجد ما كنت تبحث عنه ولا فائدة من الاستمرار.

// إيجاد أوّل عدد زوجي في مصفوفة int[] numbers = {3, 7, 11, 4, 9, 2}; int firstEven = -1; for (int n : numbers) { if (n % 2 == 0) { firstEven = n; break; // نتوقّف فور إيجاد القيمة } } System.out.println("First even: " + firstEven); // 4

بدون break ستستمر الحلقة في المرور على 9 و2 رغم أنّ الإجابة معروفة منذ 4.

break لا يخرج إلا من مستوى واحد. لو كانت هذه الحلقة متداخلة داخل حلقة أخرى، فسيخرج break من الحلقة الداخلية فقط، وستستمر الخارجية. سنتناول ذلك في قسم التسمية أدناه.

continue — تخطّي دورة واحدة

لا يُنهي continue الحلقة — بل يتخطّى ما تبقّى من جسم الدورة الحالية ويقفز مباشرةً إلى خطوة التحديث (في for) أو العودة لفحص الشرط (في while). استخدمه حين تكون قيمة معيّنة غير مثيرة للاهتمام وتريد تجاوزها.

// طباعة الأعداد الفردية فقط من 1 إلى 10 for (int i = 1; i <= 10; i++) { if (i % 2 == 0) { continue; // تخطّي الأعداد الزوجية } System.out.print(i + " "); } // الناتج: 1 3 5 7 9
فضّل الشروط الإيجابية متى أمكن. يمكن كتابة نفس الحلقة بـ if (i % 2 != 0) { System.out.print(i + " "); } دون continue. استخدم continue حين يُبسّط المنطق فعلًا — مثلًا حين يتخطّى عدة أسطر من العمل.

break مقابل continue في لمحة سريعة

  • break — اخرج من الحلقة كليًّا وتابع ما بعدها.
  • continue — تخطّ ما تبقّى من هذه الدورة ثم تحقّق من الشرط مجدّدًا.

break المسمّى — الهروب من الحلقات المتداخلة

الحلقات المتداخلة شائعة في اجتياز المصفوفات ثنائية الأبعاد وعمليات البحث في الشبكات. حين تجد هدفك داخل الحلقة الداخلية، فإنّ break العادي يخرج من الحلقة الداخلية فقط وتستمر الخارجية. يتيح لك break المسمّى الخروج من الحلقتَين معًا دفعةً واحدة.

التسمية مجرّد معرّف يتبعه نقطتان، يُوضع مباشرةً قبل الحلقة التي تريد القدرة على الخروج منها:

// البحث عن قيمة في شبكة ثنائية الأبعاد int[][] grid = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} }; int target = 5; int foundRow = -1, foundCol = -1; outer: // تسمية للحلقة الخارجية for (int row = 0; row < grid.length; row++) { for (int col = 0; col < grid[row].length; col++) { if (grid[row][col] == target) { foundRow = row; foundCol = col; break outer; // يخرج من كلتا الحلقتَين } } } System.out.println("Found at row=" + foundRow + ", col=" + foundCol); // Found at row=1, col=1

بعد break outer ينتقل Java إلى أوّل سطر بعد الحلقة for الخارجية — لن تُزار الصفّ رقم 2 أبدًا.

continue المسمّى — إعادة تشغيل الحلقة الخارجية

يمكنك أيضًا استخدام التسمية مع continue. بدلًا من الانتقال إلى الدورة التالية في الحلقة الداخلية، ينتقل Java إلى الدورة التالية في الحلقة المسمّاة (الخارجية).

// تخطّي أي صفّ يحتوي على عدد سالب int[][] data = { {1, 2, 3}, {4, -1, 6}, // تخطّي هذا الصفّ {7, 8, 9} }; rows: for (int r = 0; r < data.length; r++) { for (int c = 0; c < data[r].length; c++) { if (data[r][c] < 0) { continue rows; // انتقل للصفّ التالي فورًا } } // لا يُصل إلى هنا إلا إذا لم يوجد سالب في الصفّ System.out.println("Clean row " + r); } // Clean row 0 // Clean row 2

مكان وضع التسميات

يجب وضع التسميات مباشرةً قبل جملة حلقة (for أو while أو do-while). لا يمكنها تسمية كتل اعتباطية. بالاتفاق، تُكتب أسماء التسميات بأحرف صغيرة (outer، rows) تمييزًا لها عن الثوابت.

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

مثال متكامل — مسودّة منخل الأعداد الأوّلية

إليك مقطعًا يستخدم break وcontinue معًا: يفحص كل عدد مرشّح ويتخطّى المركّبة منها بـ continue، ثم يتوقّف عند أوّل عدد أوّلي فوق حدّ معيّن.

int limit = 50; int firstPrimeAbove40 = -1; candidates: for (int n = 41; n <= limit; n++) { for (int d = 2; d * d <= n; d++) { if (n % d == 0) { continue candidates; // n مركّب — جرّب المرشّح التالي } } // نصل هنا فقط إذا لم يُوجد قاسم firstPrimeAbove40 = n; break candidates; // وجدناه — أوقف الحلقة الخارجية أيضًا } System.out.println("First prime above 40 (up to " + limit + "): " + firstPrimeAbove40); // First prime above 40 (up to 50): 41

الخلاصة

  • break يخرج من أعمق حلقة فورًا.
  • continue يتخطّى ما تبقّى من الدورة الحالية ويكمل.
  • break المسمّى يخرج من حلقة خارجية بعينها عبر اسمها.
  • continue المسمّى يُعيد تشغيل الدورة التالية في الحلقة الخارجية المسمّاة.
  • التسميات أداة قوية — استخدمها حين تُبسّط المنطق فعلًا، وفكّر في دالة مساعدة بديلًا عنها في الحالات المعقّدة.