Перейти к основному содержимому

Выход из вложенных циклов

· 4 мин. чтения

1. Обзор

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

2. Проблема

Вложенные циклы очень полезны, например, для поиска в списке списков.

Одним из примеров может быть список студентов, где у каждого студента есть список запланированных курсов. Допустим, мы хотим найти имя одного человека, который запланировал курс 0 .

Во-первых, мы просматриваем список студентов. Затем внутри этого цикла мы перебирали список запланированных курсов.

Когда мы напечатаем имена студентов и курсов, мы получим следующий результат:

student 0
course 0
course 1
student 1
course 0
course 1

Мы хотели найти первого студента, запланировавшего курс 0 . Однако, если мы просто используем циклы, приложение продолжит поиск после того, как курс будет найден.

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

3. Перерыв

Первый вариант выхода из вложенного цикла — просто использовать оператор break :

String result = "";
for (int outerCounter = 0; outerCounter < 2; outerCounter++) {
result += "outer" + outerCounter;
for (int innerCounter = 0; innerCounter < 2; innerCounter++) {
result += "inner" + innerCounter;
if (innerCounter == 0) {
break;
}
}
}
return result;

У нас есть внешний цикл и внутренний цикл, оба цикла имеют две итерации. Если счетчик внутреннего цикла равен 0, мы выполняем команду break . Когда мы запустим пример, он покажет следующий результат:

outer0inner0outer1inner0

Или мы могли бы изменить код, чтобы сделать его немного более читабельным:

outer 0
inner 0
outer 1
inner 0

Это то, чего мы хотим?

Почти внутренний цикл завершается оператором break после того, как будет найден 0. Однако внешний цикл продолжается, а это не то, что нам нужно. Мы хотим полностью прекратить обработку, как только получим ответ.

4. Помеченный разрыв

Предыдущий пример был шагом в правильном направлении, но нам нужно его немного улучшить. Мы можем сделать это, используя помеченный break :

String result = "";
myBreakLabel:
for (int outerCounter = 0; outerCounter < 2; outerCounter++) {
result += "outer" + outerCounter;
for (int innerCounter = 0; innerCounter < 2; innerCounter++) {
result += "inner" + innerCounter;
if (innerCounter == 0) {
break myBreakLabel;
}
}
}
return result;

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

outer0inner0

Мы можем прочитать это немного лучше с некоторым форматированием:

outer 0
inner 0

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

5. Возврат

В качестве альтернативы мы могли бы также использовать оператор return для прямого возврата результата, когда он найден:

String result = "";
for (int outerCounter = 0; outerCounter < 2; outerCounter++) {
result += "outer" + outerCounter;
for (int innerCounter = 0; innerCounter < 2; innerCounter++) {
result += "inner" + innerCounter;
if (innerCounter == 0) {
return result;
}
}
}
return "failed";

Метка удаляется, а оператор break заменяется оператором return .

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

6. Заключение

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

В качестве альтернативы мы можем использовать оператор return . Использование возврата делает код более читабельным и менее подверженным ошибкам, поскольку нам не нужно думать о разнице между немаркированными и помеченными разрывами.

Не стесняйтесь взглянуть на код на GitHub .