Основная структура оператора for
выглядит следующим образом:
BasicForStatement: for ( [ForInit] ; [Expression] ; [ForUpdate] ) Statement
Теперь из JLS §14.14.1.3. Резкое завершение for
Statement :
Если выполнение Statement завершается внезапно из-за
continue
без метки, то следующие два шаги выполняются последовательно:
- Во-первых, если присутствует ForUpdate часть, выражения оцениваются последовательно слева направо; их значения, если они есть, отбрасываются. Если ForUpdate нет, никаких действий не предпринимается.
- Во-вторых, выполняется еще один шаг итерации
for
.Если выполнение Statement завершается внезапно из-за
continue
с меткойL
, тогда есть выбор:blockquote>
- Если оператор
for
имеет меткуL
, то следующие последовательности выполняются последовательно: во-первых, если присутствует ForUpdate часть, выражения оцениваются последовательно слева направо; их значения, если они есть, отбрасываются. Если ForUpdate отсутствует, никаких действий не предпринимается. Во-вторых, выполняется еще один шаг итерацииfor
.- Если оператор
for
не имеет меткиL
, операторfor
неожиданно завершается из-за продолжения с меткойL
.(выделение мое)
ForUpdate , в вашем случае,
i++
. На основании того, что выше:
- Ваш первый фрагмент относится к первому случаю, поэтому
i
увеличивается.- Второй фрагмент подпадает под второй случай, поэтому
i
не увеличивается, потому что инструкцияfor
завершается внезапно.Обратите внимание, что если бы во втором фрагменте
continue LABEL1
,i
был бы увеличен, как в вашем первом фрагменте ( в соответствии с JLS).В качестве подсказки для будущего, для окончательных ответов относительно языковых правил / семантики, вы должны всегда проконсультироваться с языком Спецификация. Для Java это JLS .
Оператор continue
без метки будет повторно выполняться из условия, которое является самым внутренним во время или до, или циклом, и из выражения update - самым внутренним для цикла. Он часто используется для раннего завершения обработки цикла и, тем самым, для избежания глубоко вложенных операторов if. В следующем примере continue будет получать следующую строку, не обрабатывая следующий оператор в цикле.
while (getNext(line)) {
if (line.isEmpty() || line.isComment())
continue;
// More code here
}
С меткой continue будет выполняться так же, как и соответствующий петлю. Это можно использовать для выхода из глубоко вложенных циклов или просто для ясности. Если вы действительно извращены, вы также можете использовать его для имитации ограниченной формы goto
. В следующем примере continue
повторно выполнит цикл for (;;)
.
aLoopName: for (;;) {
// ...
while (someCondition)
// ...
if (otherCondition)
continue aLoopName;
Иногда continue
также используется в качестве заполнителя, чтобы очистить тело пустого контура.
for (count = 0; foo.moreData(); count++) continue;
Тот же оператор без label
также существует в C и C ++. В Perl он называется next
.
i
будет увеличено в конце внутреннего цикла. Но continue LABEL2
выпрыгивает из внутреннего цикла, до конца внешнего цикла, поэтому i
не увеличивается; вместо этого только j
увеличивается до тех пор, пока условие внешнего контура больше не будет удовлетворено.
Возможно, это становится яснее, когда мы переписываем код с помощью while
петель:
int j=0;
int i = 0;
while (j<3) {
while(i<3) {
if (true)
goto END_OF_LOOP2;
END_OF_LOOP1: i++;
}
END_OF_LOOP2: j++;
}
blockquote>
i
увеличивается, когда проверяется следующее условие времени.Если вы
continue
илиbreak
, тогда цикл не будет проверяться снова и никогда не будет увеличивайте значениеi
.для
LABEL1 : for(;i < 3; i++){ if (true) continue; }
, когда вы продолжаете, вы снова проверяете, если значение
i
меньше 3 в этот момент, прежде чем проверять, что компилятор условия внутренне увеличивает значениеi
.Здесь
LABEL2 : for(;j <3;j++){ LABEL1 : for(;i < 3; i++){ if (true) continue LABEL2; } }
Когда вы выполняете условие
continue
дляLabel1
, оно никогда не проверяется снова и будет напрямую перейдите к утверждению с помощьюLabel2
, чтобы он никогда не увеличивался.То же самое с разрывом
LABEL1 : for(;i < 3; i++){ if (true) break; }
, если вы выполняете вышеуказанное значение кода
i
, будет0
, а не1
.
Продолжение просто делает то, что предлагает его имя, оно немедленно продолжает следующее выполнение цикла без выполнения остальной части кода в цикле.
Итак, если у вас есть такой цикл:
int j=0;
int i = 0;
LABEL1 : for(;i < 3; i++){
if (true) {
continue;
}
someOtherMethod();
}
Часть someOtherMethod никогда не выполняется, потому что вы всегда будете нажимать на продолжение.
Причина, по которой ваш счетчик никогда не увеличивается, связан с метками, вы можете пометить цикл меткой (в вашем случае LABEL1
и LABEL2
и используйте эту метку, чтобы продолжить одну из внешних циклов вашего внутреннего цикла.
Таким образом, с вашим кодом цикл LABEL1
никогда не будет иметь шансов на увеличение его счетчик и, следовательно, i
остаются 0
, потому что ваш оператор продолжения немедленно продолжает следующую итерацию внешнего цикла.
Если это код, например:
int main (){
// Local variable declaration:
int a = 10;
// do loop execution
do
{
if( a == 15)
{
// skip the iteration.
a = a + 1;
continue;
}
cout << "value of a: " << a << endl;
a = a + 1;
}while( a < 20 );
return 0;
}
Тогда результатом будет
value of a: 10
value of a: 11
value of a: 12
value of a: 13
value of a: 14
value of a: 16
value of a: 17
value of a: 18
value of a: 19
ТОЧКА ДЛЯ БУМАГИ: «значение a: 15» равно а не на выходе. продолжение в языке программирования пропускает, что определенная строка в цикле, если используется «break», а затем разрывается, просто выходит из этой строки после «14» (в данном случае). Для вашего понимания см. Следующую блок-схему:
[/g0]
Если вы запустите это в режиме отладки, вы увидите, что произойдет. Короче говоря, всякий раз, когда вы вводите внутренний цикл для увеличения i
, вместо LABEL2
вместо i
вы будете вместо continue
вместо i
и переходите к следующей итерации внутреннего цикла.
Таким образом, вы будете во внешнем цикле 3 раза, и вы никогда не ударите i++
во внутреннем цикле.
Если это проще, подумайте о внутреннем цикле, как цикл while:
int i = 0, j = 0;
LABEL2: for (; j < 3; j++) {
LABEL1: while (i < 3) {
if (true) {
continue LABEL2;
}
i++;
}
}
continue LABEL2;
вызывает увеличение только внешнего цикла. если у вас
LABEL2 : for(;j <3;j++){
LABEL1 : for(;i < 3; i++){
if (true)
continue LABEL1;
}
}
i
будет увеличиваться.