У меня есть такая конструкция вложенного цикла:
for (Type type : types) {
for (Type t : types2) {
if (some condition) {
// Do something and break...
break; // Breaks out of the inner loop
}
}
}
Теперь, как я могу вырваться из обоих циклов. Я посмотрел на подобные вопросы, но никто конкретно не касается Java. Я не мог применять эти решения, потому что большинство используемых gotos.
Я не хочу поместить внутренний цикл в другой метод.
Обновление: я не хочу повторно запускать циклы, когда я ломаюсь, я закончил выполнение цикла.
Как и другие ответчики, я определенно предпочел бы поставить циклы другим способом, после чего вы можете просто вернуться, чтобы полностью прекратить итерацию. Этот ответ просто показывает, как можно удовлетворить требования в вопросе.
Вы можете использовать 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;
}
}
}
&& !finished
вместо || !finished
? И почему тогда вообще использовать break
и не использовать && !finished
для внутреннего цикла?
break
чтобы иметь возможность произвольно выйти из цикла. Если после этого есть код if
block, вы можете 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
и goto
s, вы можете использовать "традиционный" для цикла вместо "in-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;
}
}
}
Мне нужно было сделать аналогичную вещь, но я решил не использовать расширенный цикл для этого.
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**/);
Скорее в течение долгого времени я думал поделиться этим типом ответа на этот вопрос.
Обычно такие случаи входят в область более значимой логики, скажем, некоторые поиски или манипулирование некоторыми из повторяющихся "для" объектов, о которых идет речь, поэтому я обычно использую функциональный подход:
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;
}
Основные минусы:
Профи:
Таким образом, это просто обработка дела с помощью другого подхода.
В основном вопрос автору этого вопроса: что вы думаете об этом подходе?
Вы можете отключиться от всех циклов без использования метки: и flags.
Это просто сложное решение.
Здесь условие 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");
}
}
Если он внутри какой-то функции, почему бы вам просто не вернуть его:
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
}
}
Еще одно решение, упомянутое без примера (оно действительно работает в коде 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];
}
}
Используйте ярлыки.
INNER:for(int j = 0; j < numbers.length; j++) {
System.out.println("Even number: " + i + ", break from INNER label");
break INNER;
}
См. Эту статью
Демо для break
, continue
, label
.
Таким образом, слова java break
и continue
имеют значение по умолчанию, это "ближайшая петля", 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);
}
}
}
}
}
Я хотел ответить на этот вопрос, но был отмечен как дубликат, который мешает мне публиковать. Поэтому отправляйте его здесь!
Если это новая реализация, вы можете попробовать переписать логику как 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 и просто хотите получить эту работу, вы можете попробовать использовать ярлыки
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;
}
}
}
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;
}
}
Вы можете сделать следующее:
установить локальную переменную в 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
loop.
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;
}
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");
}
boolean condition = false;
for (Type type : types) {
for (int i = 0; i < otherTypes.size && !condition; i ++) {
condition = true; // if your condition is satisfied
}
}
Использовать условие как флаг для того, когда вы закончите обработку. Затем внутренний цикл продолжается, пока условие не выполнено. В любом случае внешняя петля будет продолжаться.
Вы просто используете метку для разбиения внутренних циклов
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
}
}
Я чувствую, что использование меток делает код очень похожим на инструкцию goto. Это просто мысль. Почему бы нам не сделать исключение во внутреннем цикле for и инкапсулировать два цикла for с блоком catch try. Что-то вроде
try {
// ...
for(Object outerForLoop : objectsOuter) {
// ...
for (Object innerForLoop : objectsInner) {
// ...
if (isConditionTrue)
throw new WrappedException("With some useful message. Probably some logging as well.");
}
} catch (WrappedException) {
// do something awesome or just don't do anything swallow the exception.
}
Просто мысль. Я предпочитаю этот код, так как он дает мне лучшую доступность (как это слово) для меня, когда это выполняется на производстве или что-то в этом роде.