java - لغة - شرح loop في الجافا




الخروج من الحلقات المتداخلة في جافا (20)

(EDIT: مثل غيرها من الإجابات ، أفضل بالتأكيد وضع الحلقة الداخلية بطريقة مختلفة. هذه الإجابة تظهر فقط كيف يمكن تلبية المتطلبات في السؤال.)

يمكنك استخدام break مع تسمية للحلقة الخارجية. فمثلا:

public class Test {
  public static void main(String[] args) {
    outerloop:
    for (int i=0; i < 5; i++) {
      for (int j=0; j < 5; j++) {
        if (i * j > 6) {
          System.out.println("Breaking");
          break outerloop;
        }
        System.out.println(i + " " + j);
      }
    }
    System.out.println("Done");
  }
}

هذا يطبع:

0 0
0 1
0 2
0 3
0 4
1 0
1 1
1 2
1 3
1 4
2 0
2 1
2 2
2 3
Breaking
Done

لقد حصلت على بناء حلقة متداخلة مثل هذا:

for (Type type : types) {
    for (Type t : types2) {
         if (some condition) {
             // Do something and break...
             break; // Breaks out of the inner loop
         }
    }
}

الآن كيف يمكنني الخروج من كلا الحلقتين. لقد بحثت في أسئلة مشابهة ، ولكن لا شيء يتعلق بجافا على وجه التحديد. لم أستطع تطبيق هذه الحلول لأن gotos الأكثر استخدامًا.

لا أريد أن أضع الحلقة الداخلية بطريقة مختلفة.

تحديث: لا أريد إعادة تشغيل الحلقات ، عند الانهيار ، انتهيت من تنفيذ كتلة الحلقة.


أردت أن أجيب على this السؤال ولكن تم وضع علامة عليه كمكررة مما يمنعني من النشر أيضًا. لذلك نشرها هنا بدلا من ذلك!

إذا كان تطبيق جديد يمكنك محاولة إعادة كتابة المنطق كما لو - else_if - آخر البيانات.

while(keep_going) {

    if(keep_going && condition_one_holds) {
        // code
    }
    if(keep_going && condition_two_holds) {
        // code
    }
    if(keep_going && condition_three_holds) {
        // code
    }
    if(keep_going && something_goes_really_bad) {
        keep_going=false;
    }
    if(keep_going && condition_four_holds) {
        // code
    }
    if(keep_going && condition_five_holds) {
        // code
    }   
}

وإلا يمكنك محاولة وضع علامة عندما حدث ذلك الشرط الخاص والتحقق من تلك العلامة في كل من شروط loop الخاصة بك.

something_bad_has_happened = false;
while(something is true && !something_bad_has_happened){
    // code, things happen
    while(something else && !something_bad_has_happened){
        // lots of code, things happens
        if(something happened){
            -> Then control should be returned ->
            something_bad_has_happened=true;
            continue;
        }
    }   
    if(something_bad_has_happened) { // things below will not be executed
        continue;
    }

    // other things may happen here as well but will not be executed
    //  once control is returned from the inner cycle
}

HERE! So, while a simple break will not work, it can be made to work using continue.

إذا كنت تقوم ببساطة بنقل المنطق من لغة برمجية واحدة إلى Java وترغب فقط في الحصول على شيء يعمل يمكنك محاولة استخدام labels


أفضل وأسهل طريقة ..

outerloop:
 for(int i=0; i<10; i++){
    // here we can break Outer loop by 
    break outerloop;

    innerloop:
      for(int i=0; i<10; i++){
          // here we can break innerloop by 
          break innerloop;
       }
 }

أفضّل إضافة "خروج" صريح إلى اختبارات الحلقة. إنه يوضح لأي قارئ غير رسمي أن الحلقة قد تنتهي مبكراً.

boolean earlyExit = false;
for(int i=0;i<10&&!earlyExit; i++) {
 for(int j=0;i<10&&!earlyExit; j++) { earlyExit=true; }
}

أنت فقط تستخدم تسمية لكسر الحلقات الداخلية

public class Test {
public static void main(String[] args) {
    outerloop:
for (int i=0; i < 5; i++) {
  for (int j=0; j < 5; j++) {
    if (i * j > 6) {
      System.out.println("Breaking");
      break outerloop;
    }
    System.out.println(i + " " + j);
  }
}
System.out.println("Done");
}
}

إذا كانت داخل بعض الوظائف ، فلماذا لا تعيدها فقط:

for (Type type : types) {
    for (Type t : types2) {
         if (some condition) {
            return value;
         }
    }
}


بدلاً من ذلك ، كنت أفكر في مشاركة هذا النوع من الإجابات لهذا النوع من الأسئلة.

عادة ما تأتي مثل هذه الحالات في نطاق منطق أكثر منطقية ، دعنا نقول بعض البحث أو التلاعب في بعض من 'for'- الأشياء المتكرر ، لذلك عادة ما استخدم النهج الوظيفي:

public Object searching(Object[] types) {//or manipulating
    List<Object> typesReferences = new ArrayList<Object>();
    List<Object> typesReferences2 = new ArrayList<Object>();

    for (Object type : typesReferences) {
        Object o = getByCriterion(typesReferences2, type);
        if(o != null) return o; 
    }
    return null;
}
private Object getByCriterion(List<Object> typesReferences2, Object criterion) {
    for (Object typeReference : typesReferences2) {
        if(typeReference.equals(criterion)) {
             // here comes other complex or specific logic || typeReference.equals(new Object())
             return typeReference;
        }
    }
    return null;
}

سلبيات رئيسية:

  • ما يقرب من خطوط أكثر مرتين
  • مزيد من استهلاك دورات الحوسبة ، مما يعني أنها أبطأ من نقطة العرض الخوارزمية
  • المزيد من أعمال الطباعة

الايجابيات:

  • أعلى نسبة لفصل المخاوف بسبب الدقة الوظيفية
  • نسبة أعلى من إعادة الاستخدام والتحكم في منطق البحث / التلاعب دون
  • الأساليب ليست طويلة ، وبالتالي فهي أكثر إحكاما وأسهل للفهم
  • نسبة عالية ذاتي القراءة

لذلك فقط يتم التعامل مع القضية من خلال نهج مختلف.

في الأساس سؤال لصاحب هذا السؤال: ما هو رأيك في هذا النهج؟


حتى إنشاء علامة للحلقة الخارجية والتحقق من أنه بعد كل تنفيذ الحلقة الداخلية يمكن أن يكون الجواب.

مثله :

for (Type type : types) {
      boolean flag=false;
         for (Type t : types2) {
                if (some condition) {
                    // Do something and break...
                    flag=true;
                    break; // Breaks out of the inner loop
                }
            }
            if(flag)
                break;
        }

حل Java 8 Stream:

List<Type> types1 = ...
List<Type> types2 = ...

types1.stream()
      .flatMap(type1 -> types2.stream().map(type2 -> new Type[]{type1, type2}))
      .filter(types -> /**some condition**/)
      .findFirst()
      .ifPresent(types -> /**do something**/);

ربما مع وظيفة؟

public void doSomething(List<Type> types, List<Type> types2){
  for(Type t1 : types){
    for (Type t : types2) {
      if (some condition) {
         //do something and return...
         return;
      }
    }
  }
}

طريقة غير معتادة ولكن من حيث طول الشفرة ( وليس الأداء ) ، هذا هو أسهل ما يمكنك القيام به:

for(int i=0; i++; i<j){
    if(wanna exit){
        i=i+j; //if more nested, also add the 
               //maximum value for the other loops
    }
}

في بعض الحالات ، يمكننا استخدام حلقة مستمرة بشكل فعال هنا.

  Random rand = new Random();
  //Just an example
  for (int k = 0; k < 10; ++k) {
    int count = 0;
    while (!(rand.nextInt(200) == 100)) {
       count++;
    }

    results[k] = count;
  }

كنت بحاجة إلى القيام بشيء مماثل ، لكنني اخترت عدم استخدام حلقة المعززة للقيام بذلك.

int s = type.size();
for (int i = 0; i < s; i++) {
    for (int j = 0; j < t.size(); j++) {
        if (condition) {
            // do stuff after which you want 
            // to completely break out of both loops
            s = 0; // enables the _main_ loop to terminate
            break;
        }
    }
}

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

من شأنه أن يؤتي ثماره من أجل القراءة.

سيصبح الرمز شيئًا كالتالي:

private static String search(...) 
{
    for (Type type : types) {
        for (Type t : types2) {
            if (some condition) {
                // Do something and break...
                return search;
            }
        }
    }
    return null; 
}

مطابقة المثال للإجابة المقبولة:

 public class Test {
    public static void main(String[] args) {
        loop();
        System.out.println("Done");
    }

    public static void loop() {
        for (int i = 0; i < 5; i++) {
            for (int j = 0; j < 5; j++) {
                if (i * j > 6) {
                    System.out.println("Breaking");
                    return;
                }
                System.out.println(i + " " + j);
            }
        }
    }
}

يمكنك استخدام التصنيفات:

label1: 
    for (int i = 0;;) {
        for (int g = 0;;) {
          break label1;
        }
    }

يمكنك استخدام متغير مؤقت:

boolean outerBreak = false;
for (Type type : types) {
   if(outerBreak) break;
    for (Type t : types2) {
         if (some condition) {
             // Do something and break...
             outerBreak = true;
             break; // Breaks out of the inner loop
         }
    }
}

اعتمادا على وظيفتك ، يمكنك أيضا الخروج / العودة من الحلقة الداخلية:

for (Type type : types) {
    for (Type t : types2) {
         if (some condition) {
             // Do something and break...
             return;
         }
    }
}

يمكنك الخروج من كل الحلقات دون استخدام أي ملصق: والأعلام.

انها مجرد حل صعب.

هنا condition1 هي الشرط الذي يتم استخدامه للكسر من الحلقة K و J. و condition2 هي الشرط الذي يتم استخدامه لكسر الحلقة K و J و I.

فمثلا:

public class BreakTesting {
    public static void main(String[] args) {
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                for (int k = 0; k < 9; k++) {
                    if (condition1) {
                        System.out.println("Breaking from Loop K and J");
                        k = 9;
                        j = 9;
                    }
                    if (condition2) {
                        System.out.println("Breaking from Loop K, J and I");
                        k = 9;
                        j = 9;
                        i = 9;
                    }
                }
            }
        }
        System.out.println("End of I , J , K");
    }
}

for (int j = 0; j < 5; j++) //inner loop يجب استبدال for (int j = 0; j < 5; j++) //inner loop for (int j = 0; j < 5 && !exitloops; j++) .

هنا ، في هذه الحالة يجب أن تكون الحلقات المتداخلة كاملة إذا كان الشرط True . ولكن إذا استخدمنا exitloops فقط إلى loop العليا

 for (int i = 0; i < 5 && !exitloops; i++) //upper loop

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

مثال: إذا كان i = 3 و j=2 فإن الشرط غير false . ولكن في التكرار التالي للحلقة الداخلية j=3 فإن الشرط (i*j) يصبح 9 وهو true ولكن الحلقة الداخلية سوف تستمر حتى يصبح j 5 .

لذلك ، يجب أن تستخدم exitloops إلى الحلقات الداخلية أيضا.

    boolean exitloops= false;
    for (int i = 0; i < 5 && !exitloops; i++) { //here should exitloops as a Conditional Statement to get out from the loops if exitloops become true. 
        for (int j = 0; j < 5 && !exitloops; j++) { //here should also use exitloops as a Conditional Statement. 
            if (i * j > 6) {
                exitloops = true;
                System.out.println("Inner loop still Continues For i * j is => "+i*j);
                break;
            }
            System.out.println(i*j);
        }
    }

boolean broken = false; // declared outside of the loop for efficiency
for (Type type : types) {
    for (Type t : types2) {
        if (some condition) {
            broken = true;
            break;
        }
    }

    if (broken) {
        break;
    }
}




loops