Как вырваться из вложенных циклов в Java?

У меня есть конструкция вложенного цикла, как это:

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

Теперь, как я могу вырваться из обеих петель? Я смотрел на похожие вопросы, но ни один из них не касается конкретно Java. Я не мог применить эти решения, потому что большинство использовали gotos.

Я не хочу помещать внутренний цикл в другой метод.

Я не хочу перезапускать циклы. При разрыве я заканчиваю выполнение цикла цикла.

38 ответов

Решение

Как и другие ответчики, я бы определенно предпочел поместить циклы в другой метод, после чего вы можете просто вернуться, чтобы полностью прекратить итерации. Этот ответ просто показывает, как требования в вопросе могут быть выполнены.

Ты можешь использовать 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

Технически правильный ответ - обозначить внешний цикл. На практике, если вы хотите выйти в любой точке внутреннего цикла, вам лучше было бы перенести код в метод (статический метод, если это необходимо), а затем вызвать его.

Это окупится за удобочитаемость.

Код станет примерно таким:

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);
            }
        }
    }
}

Вы можете использовать именованный блок вокруг циклов:

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

Я никогда не использую ярлыки. Кажется, это плохая практика. Вот что я бы сделал:

boolean finished = false;
for (int i = 0; i < 5 && !finished; i++) {
    for (int j = 0; j < 5; j++) {
        if (i * j > 6) {
            finished = true;
            break;
        }
    }
}

Вы можете использовать ярлыки:

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

Используйте функцию:

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;
      }
    }
  }
}

Вы можете использовать временную переменную:

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;
         }
    }
}

Использование одного ключевого слова break не является подходящим способом, когда вам нужно выйти из более чем одного цикла. Вы можете выйти из непосредственного цикла. Независимо от того, сколько циклов окружает ваш оператор. Вы можете использовать "разрыв" с меткой! Здесь я использовал метку "abc". Вы можете написать свой код, как показано ниже, в любой функции Java.

Этот код показывает, как выйти из самого внешнего цикла

 abc: 
    for (int i = 0; i < 10; i++) { 
        for (int j = 0; j < 10; j++) { 
           for (int k = 0; k < 10; k++) { 
              if (k == 1){
                 break abc;
              } 
        } 
    } 
}

Также вы можете использовать оператор break для выхода из любого цикла вложенного цикла.

    for (int i = 0; i < 10; i++) { 
       abc:for (int j = 0; j < 10; j++) { 
           for (int k = 0; k < 10; k++) { 
              if (k == 1){
                 break abc;
              } 
        } 
    } 
}

В следующем коде показан пример выхода из самого внутреннего цикла. В других работах после выполнения следующего кода вы находитесь за пределами цикла переменных "k" и по-прежнему внутри цикла переменных "j" и "i".

    for (int i = 0; i < 10; i++) { 
        for (int j = 0; j < 10; j++) { 
           for (int k = 0; k < 10; k++) { 
              if (k == 1){
                 break;
              } 
        } 
    } 
}

Если тебе не нравится breakс и gotos, вы можете использовать "традиционный" цикл for вместо for-in с дополнительным условием прерывания:

int a, b;
bool abort = false;
for (a = 0; a < 10 && !abort; a++) {
    for (b = 0; b < 10 && !abort; b++) {
        if (condition) {
            doSomeThing();
            abort = true;
        }
    }
}

Мне нужно было сделать аналогичную вещь, но я решил не использовать расширенный цикл for, чтобы сделать это.

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;
        }
    }
}

Я предпочитаю добавить явный "выход" к тестам цикла. Любой случайный читатель дает понять, что цикл может закончиться рано.

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

Концепция размеченного разрыва используется для разрыва вложенных циклов в Java, с помощью размеченного разрыва вы можете разорвать вложение циклов в любой позиции. Пример 1:

loop1:
 for(int i= 0; i<6; i++){
    for(int j=0; j<5; j++){
          if(i==3)
            break loop1;
        }
    }

предположим, что есть 3 цикла, и вы хотите завершить цикл 3: Пример 2:

loop3: 
for(int i= 0; i<6; i++){
loop2:
  for(int k= 0; k<6; k++){
loop1:
    for(int j=0; j<5; j++){
          if(i==3)
            break loop3;
        }
    }
}

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 static void main(String[] args) {
    outer:
    while (true) {
        while (true) {
            break outer;
        }
    }
}

Скорее всего, я долго думал о том, чтобы ответить на этот вопрос.

Обычно такие случаи входят в сферу более осмысленной логики, скажем, некоторого поиска или манипулирования некоторыми итеративными объектами 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;
}

Основные минусы:

  • примерно в два раза больше строк
  • больше потребления вычислительных циклов, что означает, что он медленнее с алгоритмической точки зрения
  • больше печатать работу

Плюсы:

  • более высокое отношение к разделению интересов из-за функциональной детализации
  • более высокий коэффициент повторного использования и управления поиском / манипулированием логикой без
  • методы не длинные, поэтому они более компактны и их легче понять
  • субъективно более высокий коэффициент читабельности

Так что это просто обработка дела с помощью другого подхода.

В основном вопрос к автору этого вопроса: что вы думаете об этом подходе?

Вы можете выйти из всех циклов, не используя метки: и флаги.

Это просто хитрое решение.

Здесь условие 1 - это условие, которое используется для выхода из цикла K и J, а условие 2 - это условие, которое используется для выхода из цикла 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");
    }
}

Используйте ярлыки.

INNER:for(int j = 0; j < numbers.length; j++) {
    System.out.println("Even number: " + i + ", break  from INNER label");
    break INNER;
}

Обратитесь к этой статье

Лучший и простой метод..

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;
     }
}

Довольно легко использовать label, Вы можете прервать внешний цикл из внутреннего, используя метку. Рассмотрим пример ниже.

public class Breaking{
    public static void main(String[] args) {
        outerscope:
        for (int i=0; i < 5; i++) {
            for (int j=0; j < 5; j++) {
                if (condition) {
                    break outerscope;
                }
            }
        }
    }
}

Другой подход - использовать переменную / флаг прерывания для отслеживания необходимого прерывания. рассмотрим следующий пример.

public class Breaking{ 
    public static void main(String[] args) {
        boolean isBreaking = false;
        for (int i=0; i < 5; i++) {
            for (int j=0; j < 5; j++) {
                if (condition) {
                    isBreaking = true;
                    break;
                }
            }
            if(isBreaking){
                break;
            }
        }
    }
}

Однако я предпочитаю использовать первый подход.

Если это внутри какой-то функции, почему бы вам просто не вернуть ее:

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

Довольно необычный подход, но с точки зрения длины кода (не производительности) это самое простое, что вы можете сделать:

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
    }
}
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;
    }
}

Другое решение, упомянутое без примера (на самом деле оно работает в коде prod).

try {
    for (Type type : types) {
        for (Type t : types2) {
            if (some condition #1) {
                // Do something and break the loop.
                throw new BreakLoopException();
            }
        }
    }
}
catch (BreakLoopException e) {
    // Do something on look breaking.
}

Конечно BreakLoopException должен быть внутренним, частным и ускоренным без трассировки стека:

private static class BreakLoopException extends Exception {
    @Override
    public StackTraceElement[] getStackTrace() {
        return new StackTraceElement[0];
    }
}

Демо для break, continue, label,

Так что Java ключевые слова break а также continue есть значение по умолчанию, это "Nearest Loop", Toady через несколько лет после использования Java, я только что понял!

Кажется, используется редко, но полезно.

import org.junit.Test;

/**
 * Created by cui on 17-5-4.
 */

public class BranchLabel {
    @Test
    public void test() {
        System.out.println("testBreak");
        testBreak();

        System.out.println("testBreakLabel");
        testBreakLabel();

        System.out.println("testContinue");
        testContinue();

        System.out.println("testContinueLabel");
        testContinueLabel();

    }

    /**
     testBreak
     a=0,b=0
     a=0,b=1
     a=1,b=0
     a=1,b=1
     a=2,b=0
     a=2,b=1
     a=3,b=0
     a=3,b=1
     a=4,b=0
     a=4,b=1
     */
    public void testBreak() {
        for (int a = 0; a < 5; a++) {
            for (int b = 0; b < 5; b++) {
                if (b == 2) {
                    break;
                }
                System.out.println("a=" + a + ",b=" + b);
            }
        }
    }

    /**
     testContinue
     a=0,b=0
     a=0,b=1
     a=0,b=3
     a=0,b=4
     a=1,b=0
     a=1,b=1
     a=1,b=3
     a=1,b=4
     a=2,b=0
     a=2,b=1
     a=2,b=3
     a=2,b=4
     a=3,b=0
     a=3,b=1
     a=3,b=3
     a=3,b=4
     a=4,b=0
     a=4,b=1
     a=4,b=3
     a=4,b=4
     */
    public void testContinue() {
        for (int a = 0; a < 5; a++) {
            for (int b = 0; b < 5; b++) {
                if (b == 2) {
                    continue;
                }
                System.out.println("a=" + a + ",b=" + b);
            }
        }
    }

    /**
     testBreakLabel
     a=0,b=0,c=0
     a=0,b=0,c=1
     * */
    public void testBreakLabel() {
        anyName:
        for (int a = 0; a < 5; a++) {
            for (int b = 0; b < 5; b++) {
                for (int c = 0; c < 5; c++) {
                    if (c == 2) {
                        break anyName;
                    }
                    System.out.println("a=" + a + ",b=" + b + ",c=" + c);
                }
            }
        }
    }

    /**
     testContinueLabel
     a=0,b=0,c=0
     a=0,b=0,c=1
     a=1,b=0,c=0
     a=1,b=0,c=1
     a=2,b=0,c=0
     a=2,b=0,c=1
     a=3,b=0,c=0
     a=3,b=0,c=1
     a=4,b=0,c=0
     a=4,b=0,c=1
     */
    public void testContinueLabel() {
        anyName:
        for (int a = 0; a < 5; a++) {
            for (int b = 0; b < 5; b++) {
                for (int c = 0; c < 5; c++) {
                    if (c == 2) {
                        continue anyName;
                    }
                    System.out.println("a=" + a + ",b=" + b + ",c=" + c);
                }
            }
        }
    }

}

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);
    }
}

Как и предложение @1800 INFORMATION, используйте условие, которое разрывает внутренний цикл, как условие для внешнего цикла:

boolean hasAccess = false;
for (int i = 0; i < x && hasAccess == false; i++){
    for (int j = 0; j < y; j++){
        if (condition == true){
            hasAccess = true;
            break;
        }
    }
}

Я хотел ответить на этот вопрос, но был помечен как дубликат, который также не позволяет мне писать. Так что разместив это здесь вместо этого!

Если это новая реализация, вы можете попробовать переписать логику в виде операторов if-else_if-else.

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
    }   
}

В противном случае вы можете попробовать установить флаг, когда это специальное условие произошло, и проверить его в каждом из ваших условий цикла.

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 и просто хотите, чтобы все заработало, вы можете попробовать использовать метки

В Java нет функции перехода, как в C++. Но до сих пор, goto является зарезервированным ключевым словом в Java. Они могут реализовать это в будущем. На ваш вопрос ответ таков: в Java есть нечто, называемое меткой, к которой вы можете применить continue а также break заявление. Найдите код ниже:

public static void main(String ...args) {
    outerLoop: for(int i=0;i<10;i++) {
    for(int j=10;j>0;j--) {
        System.out.println(i+" "+j);
        if(i==j) {
            System.out.println("Condition Fulfilled");
            break outerLoop;
        }
    }
    }
    System.out.println("Got out of the outer loop");
}

Вы можете сделать следующее:

  1. установить локальную переменную в false

  2. установить эту переменную true в первом цикле, когда вы хотите разорвать

  3. тогда вы можете проверить во внешнем цикле, что, если условие установлено, то и выход из внешнего цикла тоже.

    boolean isBreakNeeded = false;
    for (int i = 0; i < some.length; i++) {
        for (int j = 0; j < some.lengthasWell; j++) {
            //want to set variable if (){
            isBreakNeeded = true;
            break;
        }
    
        if (isBreakNeeded) {
            break; //will make you break from the outer loop as well
        }
    }
    

Даже создание флага для внешнего цикла и проверка того, что после каждого выполнения внутреннего цикла может быть ответом.

Как это:

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;
}
Другие вопросы по тегам