Как вырваться из вложенных циклов в Java?
У меня есть вложенная конструкция цикла, как это:
for (Type type : types) {
for (Type t : types2) {
if (some condition) {
// Do something and break...
break; // Breaks out of the inner loop
}
}
}
теперь, как я могу выйти из обоих циклов. Я рассматривал подобные вопросы, но ни один из них не касается Java конкретно. Я не мог применить эти решения, потому что большинство используемых Гото.
Я не хочу помещать внутренний цикл в другой метод.
Update: я не хочу повторно запускать циклы, при разрыве я закончил выполнение блока цикла.
30 ответов:
как и другие ответчики, я бы определенно предпочитаю чтобы поместить внутренний цикл в другой метод. Этот ответ просто показывает, как требования в вопросе могут быть выполнены.
можно использовать
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; } } }
может быть, функция?
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; } } }
Если вам не нравится
breaks и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 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**/);
вы можете отдохнуть от всех петель без использования каких-либо меток и флагов.
Это просто хитрое решение.
здесь 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 " -объектов, о которых идет речь, поэтому я обычно использую функциональный подход:
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) { for (Type t : types2) { if (some condition) { return value; } } }
лучший и простой способ..
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; } }
довольно необычный подход, но с точки зрения длины кода (а не) это самое простое, что можно сделать:
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 } }
Использовать Метки.
INNER:for(int j = 0; j < numbers.length; j++) { System.out.println("Even number: " + i + ", break from INNER label"); break INNER; }смотрите в этой статье
еще одно решение, упомянутое без примера (оно фактически работает в коде 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]; } }
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; } }
Я хотел ответить этой вопрос, но был отмечен как дубликат, который также мешает мне публиковать. Поэтому разместите его здесь вместо этого !
если его новая реализация вы можете попробовать переписать логику как операторы 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 и просто хотите, чтобы все работало, вы можете попробовать использовать метки
демо
break,continue,label.Итак, ключевые слова java
breakиcontinueимеют значение по умолчанию, это "ближайший цикл", подхалим через несколько лет после использования 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++).здесь, в этом случае полные вложенные циклы должны быть exit, если условие
True. Но если мы используемexitloopsтолько до верхнегоloopfor (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 информационное предложение, используйте условие, которое нарушает внутренний цикл в качестве условия на внешнем цикле:
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; } } }
вы можете сделать следующее:
установите локальную переменную в
falseустановлено, что переменная
trueв первом цикле, когда вы хотите сломатьзатем вы можете проверить во внешнем цикле, что ли условие установлено, а затем вырваться из внешнего цикла, а также.
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 } }
в некоторых случаях, мы можем использовать
whileцикл эффективно здесь.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; }
даже создание флага для внешнего цикла и проверка того, что после каждого выполнения внутреннего цикла может быть ответ.
такой :
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; }
boolean condition = false; for (Type type : types) { for (int i = 0; i < otherTypes.size && !condition; i ++) { condition = true; // if your condition is satisfied } }использовать условие в качестве флага, когда вы закончите обработку. Затем внутренний цикл продолжается, пока условие не было выполнено. В любом случае внешняя петля будет продолжать пыхтеть.
Java не имеет функции goto, как в C++. Но все же,
gotoявляется зарезервированным ключевым словом в Java. Они могут реализовать его в будущем. Для вашего вопроса ответ заключается в том, что в Java есть что-то под названием label, к которому вы можете применить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"); }
вы просто используете метку для разрыва внутренних петель
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"); } }
Проверьте, выходит ли внутренний цикл с помощью оператора if, проверив переменную внутреннего цикла. Вы также можете создать другую переменную, такую как логическое значение, чтобы проверить, вышел ли внутренний цикл.
в этом примере он использует переменную внутреннего цикла, чтобы проверить, если он был выведен:
int i, j; for(i = 0; i < 7; i++){ for(j = 0; j < 5; j++) { if (some condition) { // Do something and break... break; // Breaks out of the inner loop } } if(j < 5){ // Checks if inner loop wasn't finished break; // Breaks out of the outer loop } }
Comments