Найти в Дзене

Крутой курс Java для "чайников". Урок 16. Цикл for.

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

Вообще что такое цикл?

Цикл - это часть кода, блок команд, который выполняется с определённой периодичностью снова и снова до тех пор, пока соблюдается определённое условие. Как только условие перестаёт соблюдаться, цикл завершается и программа переходит к выполнению следующих команд.

Та часть кода, которая повторяется, называется телом цикла. Одно выполнение тела цикла называется итерацией.

Существуют несколько вариантов циклов. В текущем уроке мы рассмотрим цикл for.

Синтаксис у него следующий

for (начальное значение ; проверочное выражение ; оператор счётчика )

{

код для выполнения на каждой итерации

}

Как это работает.

1. Присваиваем начальное значение переменной-счётчику. Объявить её можно прямо здесь в круглых скобках. Обычно это целочисленная переменная.

2. Определяемся с проверочным выражением. Пока значение выражение будет true, т.е. пока оно верно, код для выполнения будет исполняться снова и снова.

Другими словами, в начале каждой итерации проверочное выражение проверяется на значение true или false.

Если значение true, то исполняется код, расположенный в фигурных скобках.

Как только значение перестаёт быть true и становится false, цикл немедленно завершает свою работу, код в фигурных скобках не выполняется и программа выходит из цикла за пределы фигурных скобок.

3. Оператор счётчика изменяет текущее значение переменной-счётчика по заданному нами правилу.

Теперь на конкретном примере.

Допустим, стоит задача вывести на экран числа от 1 до 10. Каждую цифру с новой строки.

Можно эту задачу решить с помощью только оператора вывода текста на экран следующими командами:

System.out.println(1);

System.out.println(2);

System.out.println(3);

System.out.println(4);

System.out.println(5);

System.out.println(6);

System.out.println(7);

System.out.println(8);

System.out.println(9);

System.out.println(10);

Это конечно классно, когда чисел 10. А если их 100? А если 1000? Есть подозрение, что код программы будет несколько громоздким.

Есть более простое и элегантное решение - использовать цикл.

Для решения нашей конкретной задачи код будет следующим

for (int i = 1; i <= 10 ; i++)

{

System.out.println(i);

}

Давайте подробно разберём эту конструкцию, как она работает.

Программа входит в цикл.

Первая итерация

int i = 1 - объявляем переменную-счётчик i и присваиваем ей начальное значение 1.

i <= 10 осуществляется проверка проверочного условия. На первой итерации значение переменной-счётчика i равно единице. Значит, условие i <= 10 , то есть 1 <= 10 выполняется, его значение - true. Значит, тело цикла

System.out.println(i);

выполнится.

В результате выполнения тела цикла на экран с помощью оператора вывода текста будет выведено значение переменной i. На первой итерации оно равно 1. Значит, на экран будет выведено значение 1.

Тело цикла выполнилось, теперь пора выполниться оператору счётчика i++. В нашем случае оператор счётчика (инкремент) увеличил значение переменной-счётчика i на 1.

После выполнения цикла значение переменной-счётчика стало равно 2.

Всё. Первая итерация цикла выполнена. Переходим ко второй итерации.

На второй итерации переменной-счётчику уже не будет присваиваться начального значения. Оно было присвоено на входе в цикл.

Сразу осуществляется проверка проверочного условия. На второй итерации значение переменной-счётчика i равно 2. Условие i <=10, т.е. 2 <= 10 выполняется. Значит, выполнится тело цикла

System.out.println(i);

В результате выполнения тела цикла на экран будет выведено значение переменной-счётчика i, которое на второй итерации равно 2.

Тело цикла выполнилось, соответственно, опять пора выполниться оператору счётчика i++. После его выполнения значение переменной i увеличилось на 1 и стало равно 3.

Всё. Вторая итерация полностью выполнена. Переходим к третьей.

Проверочное условие i <= 10, т.е. 3 <= 10 верно. Тело цикла выполняется.

System.out.println(i);

В результате его выполнения на экран будет выведено значение переменной i, которое на третьей итерации равно 3.

Далее сработает оператор счётчика i++ и значение переменной i станет равно 4.

И так далее. Пока проверочное условие верно тело цикла будет выполняться снова и снова.

Рассмотрим 10-ю итерацию.

По результату выполнения 9-й итерации, проследив закономерность, мы можем сделать вывод, что значение переменной-счётчика будет равно 10.

Итак, начинаем 10-ю итерацию.

Выполняем 10-ю итерацию.

Проверочное условие i<=10, то есть 10 <= 10 пока ещё выполняется. Значит, тело цикла выполнится в 10-й раз. На экран будет выведено значение переменной i, равное 10.

После выполнения тела цикла в очередной раз сработает оператор счётчика и значение переменной i ещё раз будет увеличено на 1 и станет равно 11.

Далее после проверки на истинность проверочного условия 11 <= 10 будет установлено, что оно ложно, т.е. имеет значение false. Соответственно, 11-я итерация выполняться не будет, программа выйдет из цикла. Программа продолжит выполнять операторы, расположенные после закрывающейся фигурной скобки }

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

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

Итак, какие есть особенности.

1. Есть возможность дальше использовать переменную i и её значение. После последней 10-й итерации её значение стало равно 11. Его и можно использовать в случае необходимости.

2. Оператор счётчика необязательно должен быть инкрементом или декрементом.

Могут быть такие конструкции:

Вместо инкремента i = i + 1;

Это будет выглядеть так

for ( int i = 1; i <= 10 ; i = i + 1)

Результат будет таким же.

Или аналог декремента for ( int i = 1; i <= 10 ; i = i - 1)

И необязательно должна быть единица, и можно использовать не только плюс и минус.

Можно так

for ( int i = 1; i <= 10 ; i = i + 5)

А можно так

for ( int i = 1; i <= 10 ; i = i * 7)

3. Начинающие программисты часто допускают одну из двух или обе ошибки сразу. Заключаются они в следующем.

  • Цикл повторяется на одну итерацию больше или на одну итерацию меньше, чем изначально задумывалось. Как правило это происходит из-за использования некорректного оператора сравнения. Например, нужно использовать <=, а используется <. Или наоборот.

Самый простой пример - это выше рассмотренный. Хотим вывести на экран числа от 1 до 10. Правильный код

for ( int i = 1; i <= 10 ; i++)

{

System.out.println(i);

}

А часто можно перепутать и написать так:

for ( int i = 1; i < 10 ; i++)

{

System.out.println(i);

}

Что же будет, если написать так? После 9-й итерации значение i станет равно 10. После этого вроде бы должна выполниться 10-я итерация, но нет. Проверочное условие станет ложным. 10 < 10 это ложь (на всякий случай 10=10 это правда :) ). И 10-я итерация, выполнения которой мы ждём, не выполнится.

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

Опять же возьмём предыдущий пример. Вроде бы кажется, что раз на экран выводятся значения от 1 до 10, значит, после 10-й итерации значение i должно быть равно 10. Но нет. После выполнения 10-й итерации значение i увеличится на 1 и станет равно 11.

В одном из источников эту тенденцию назвали "ошибка неучтённой единицы".

3. В цикле можно пропускать одно или несколько выражений. В частности:

3.1. Переменная-счётчик может быть объявлена в самом цикле или до цикла.

Можно написать так

for (int i=1; i<10; i++)

а можно так

int i;

for (i=1; i<10; i++)

3.2. Переменной-счётчику может быть присвоено начальное значение до цикла. А в объявлении цикла можно присвоение начального значения пропустить

int i = 1;

for ( ; i<10; i++)

Результат выполнения будет таким же.

3.3. Можно не указывать оператор счётчика в скобках, а можно его указать в теле цикла.

То есть

for (int i = 1; i < 10; )

{

System.out.println(i);

i++;

}

Но если он не указан в скобках, он обязательно должен быть указан в теле цикла.

Если его не указать, то условие никогда не станет ложным. И цикл станет бесконечным.

4. Бесконечный цикл.

Код цикла должен быть составлен таким образом, чтобы в какой-то определённый момент значение проверочного выражения стало false. Иначе цикл станет так называемым бесконечным.

Например,

for (int i = 2; i != 0 ; i++)

{

i = 1;

System.out.println("Значение i = " + i);

}

Давайте подробно разберём этот пример.

Идём по порядку. Входим в цикл. Присваиваем переменной-счётчику начальное значение, предварительно объявив её. int i = 2.

Дальше выполняем проверку условия, что i не равно 0. Условие верно, значит тело цикла выполнится.

Выполняем тело цикла. Первая итерация.

Присваиваем переменной i значение 1. Да, да. Именно переменной-счётчику присваиваем новое значение.

Выводим это значение на экран в виде текста с помощью оператора вывода текста. Будет выведено

Значение i = 1

Дальше выполняется оператор счётчика. После его выполнения переменной счётчику будет присвоено значение 2 оператором инкремента.

Всё первая итерация выполнена. Переходим ко второй итерации.

Осуществляем проверку условия. Значение переменной i у нас теперь равно 2. Проверочное условие i != 0 выполняется, значит выполнится вторая итерация.

Выполняем её.

Переменной i присваиваем значение 1 командой i = 1;

Выводим на экран текст

Значение i = 1

Снова выполнится оператор счётчика. Инкрементом значение счётчика будет увеличено на 1. Снова значение i станет равно 2.

Вторая итерация завершена.

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

Другой вариант бесконечного цикла - про который упоминалось в пункте 3.3. - если не указать оператор счётчика в скобках и не указать его в теле цикла. Ещё раз пример

for (int i = 1; i < 10; )

{

System.out.println(i);

i++;

}

Так делать правильно! А так неправильно:

for (int i = 1; i < 10; )

{

System.out.println(i);

}

Как в таком случае сработает цикл?

Входим в цикл. Присваиваем переменной i начальное значение. Проверяем проверочное условие. Оно истинно. Выполняем тело цикла на первой итерации. В нашем примере это вывод на экран значения переменной i. В данном случае оно будет равно начальному значению, которое мы задали. Тело цикла выполнилось. Вроде бы должен сработать оператор счётчика. А нет. Этого не происходит. Значение i как было равно единице, так и осталось. Соответственно, произойдёт что? Начнётся вторая итерация. Опять будет проверено на истинность проверочное выражение. Опять оно будет верно. Опять будет выполнено тело цикла. И так далее. Проверочное выражение никогда не станет ложным. Соответственно, программа зациклится.

Или ещё вариант как сделать бесконечный цикл - такой:

for ( ; ; )

{

Тело цикла (любое)

}

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

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

5. Вложенные циклы

Иногда задача стоит так, что решить её можно с помощью цикла, вложенного в другой цикл. Например, такие конструкции удобно использовать при работе с массивами данных, которые будут рассмотрены в ближайших уроках.

Как это работает.

Пример конструкции с вложенным циклом

for (int a = 1; a<=3; a++)

{

System.out.println("Номер итерации внешнего цикла - " + a);

for (int b = 1; b<=3; b++)

{

System.out.println(" Номер итерации внутреннего цикла - " + b);

}

}

Здесь цикл с переменной a называется внешним циклом, цикл с переменной b - внутренний (вложенный) цикл.

Эта конструкция будет работать следующим образом.

Программа входит во внешний цикл. Переменной a присваивается начальное значение a = 1. Выполняется проверка проверочного выражения a<=3, т.е. 1 <= 3. Оно верно. Значит, тело внешнего цикла выполнится. Выполняем тело.

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

Номер итерации внешнего цикла - 1

Думаю, понятно, почему именно такой текст.

Идём по телу внешнего цикла дальше. После оператора вывода текста идёт вложенный цикл. Начинаем выполнять его.

Программа входит во внутренний цикл. Переменной b присваивается начальное значение b = 1. Выполняется проверка проверочного выражения b<=3, т.е. 1 <= 3. Оно верно. Значит, тело внутреннего цикла выполнится. Выполняем тело.

Поскольку b на первой итерации внутреннего цикла равно единице, на экран будет выведено

Номер итерации внутреннего цикла - 1

Всё. Первая итерация внутреннего цикла выполнена. После неё оператором инкремента b++ значение переменной b будет увеличено на единицу. И станет равно 2.

Проверяем проверочное выражение внутреннего цикла. b<=3, т.е. 2<=3. Верно, значит, вторая итерация внутреннего цикла выполнится. Выполняем тело внутреннего цикла второй раз. Поскольку b на второй итерации внутреннего цикла равно 2, на экран будет выведено

Номер итерации внутреннего цикла - 2

Всё. Вторая итерация внутреннего цикла выполнена. После неё оператором инкремента b++ значение переменной b будет увеличено на единицу. И станет равно 3.

Опять проверяем проверочное выражение внутреннего цикла. b<=3, т.е. 3<=3. Верно, значит, третья итерация внутреннего цикла выполнится. Выполняем тело внутреннего цикла третий раз. Поскольку b на третьей итерации внутреннего цикла равно 3, на экран будет выведено

Номер итерации внутреннего цикла - 3

Опять проверяем проверочное выражение внутреннего цикла. b<=3, т.е. 4<=3. Неверно. Значит, четвёртая итерация внутреннего цикла не будет выполнена. Всё. Внутренний цикл завершён.

Вспоминаем, что же у нас происходит с внешним циклом. У нас во внешнем цикле было 2 действия - вывести текст на экран, мы его вывели (Номер итерации внешнего цикла - 1) и выполнить внутренний цикл. Оба этих действия мы выполнили, соответственно, первая итерация внешнего цикла завершена. После её выполнения оператором инкремента a++ значение переменной a будет увеличено на 1 и станет равно 2.

Начинаем вторую итерацию внешнего цикла. Выполняем проверку проверочного выражения. a <= 3, т.е. 2 <= 3. Верно. Значит вторая итерация внешнего цикла выполнится.

Вторая итерация внешнего цикла начинается с выполнения оператора вывода текста на экран. Будет выведено:

Номер итерации внешнего цикла - 2

т.к. значение переменной a на второй итерации равно 2.

Затем после оператора вывода текста идёт цикл. Внутренний. Приступаем к его выполнению.

Опять переменной b присваивается начальное значение 1. Выполняем проверку проверочного выражения b<=3, т.е. 1 <= 3. Оно верно. Значит, тело внутреннего цикла выполнится. Выполняем тело.

Поскольку b на первой итерации внутреннего цикла равно единице, на экран будет выведено

Номер итерации внутреннего цикла - 1

Всё. Первая итерация внутреннего цикла выполнена. После неё оператором инкремента b++ значение переменной b будет увеличено на единицу. И станет равно 2.

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

Итак, теперь вкратце. Как сработает вся конструкция.

1. Первая итерация внешнего цикла.

Вывод на экран текста "Номер итерации внешнего цикла - 1"

1.1. Первая итерация внутреннего цикла

Вывод на экран текста "Номер итерации внутреннего цикла - 1"

1.2. Вторая итерация внутреннего цикла

Вывод на экран текста "Номер итерации внутреннего цикла - 2"

1.3. Третья итерация внутреннего цикла

Вывод на экран текста "Номер итерации внутреннего цикла - 3"

2. Вторая итерация внешнего цикла.

Вывод на экран текста "Номер итерации внешнего цикла - 2"

2.1. Первая итерация внутреннего цикла

Вывод на экран текста "Номер итерации внутреннего цикла - 1"

2.2. Вторая итерация внутреннего цикла

Вывод на экран текста "Номер итерации внутреннего цикла - 2"

2.3. Третья итерация внутреннего цикла

Вывод на экран текста "Номер итерации внутреннего цикла - 3"

3. Третья итерация внешнего цикла.

Вывод на экран текста "Номер итерации внешнего цикла - 3"

3.1. Первая итерация внутреннего цикла

Вывод на экран текста "Номер итерации внутреннего цикла - 1"

3.2. Вторая итерация внутреннего цикла

Вывод на экран текста "Номер итерации внутреннего цикла - 2"

3.3. Третья итерация внутреннего цикла

Вывод на экран текста "Номер итерации внутреннего цикла - 3"

6. В цикле for можно объявить и использовать как одну переменную, так и несколько.

Например,

for (int a = 1, b = 5; a != b; a++, b--)

{

System.out.println("a = " + a + ", b = " + b);

}

Обращаю внимание на вариант объявления переменных и присваивания им начальных значений - через запятую. Так тоже можно.

И операторы счётчика также можно перечислить через запятую.

Как сработает этот код.

Переменным a и b будут присвоены начальные значения.

На первой итерации цикла на экран будет выведено

a = 1, b = 5

После выполнения тела цикла выполнятся операторы счётчика. Значение переменной a будет увеличено на 1 оператором инкремента и станет равно 2. Значение переменной b будет уменьшено на 1 оператором декремента и станет равно 4.

Затем выполнится проверка проверочного выражения. Значение переменной a не равно значению переменной b. Выражение верно. Значит, выполнится вторая итерация. После выполнения тела цикла на экран будет выведено

a = 2, b = 4

Далее сработают операторы счётчика. Оператором инкремента значение переменной a увеличится на 1 и станет равно 3. Значение переменной b оператором декремента будет уменьшено на 1 и также станет равно 3.

Теперь внимание! Проверочное выражение 3 != 3 станет ложным, соответственно, в третий раз тело цикла не выполнится. Вроде бы кажется, что на экран должно быть выведено a = 3, b = 3. Но нет, этого не произойдёт, т.к. проверочное выражение ложно. Вспоминаем про описанную выше "ошибку неучтённой единицы".

7. Работу цикла можно прервать преждевременно при выполнении определённого условия с помощью ключевого слова break

Пример такой конструкции. В начале урока мы создали такой цикл

for ( int i = 1; i <= 10 ; i++)

{

System.out.println(i);

}

Он последовательно выводит на экран значения переменной i. От 1 до 10.

Можно прервать выполнение цикла, например, при значении переменной i, равном 5. Тогда конструкция будет следующей:

for ( int i = 1; i <= 10 ; i++)

{

System.out.println(i);

if (i == 5)

{

System.out.println("Выход из цикла при значении i = " + i);

break;

}

}

Результатом выполнения такого кода будет вывод на экран чисел от 1 до 5 (с 1-й по 5-ю итерацию). Затем по мере исполнения 5-й итерации программа дойдёт до исполнения оператора if. Когда условие в скобках будет истинным (при значении i, равном 5) выполнится код в фигурных скобках. Сначала выполнится оператор вывода на экран текста, на экран будет выведено "Выход из цикла при значении i = 5". Затем будет исполнен оператор break, т.е. будет осуществлен выход из цикла. Затем итерации с 6-ой по 10-ю не будут исполнены независимо от истинности проверочного выражения.

Причём, в данном случае мы сначала вывели значение переменной i (равное 5) на экран, и только после этого прервали цикл. А можно не выводить значение i на экран, а сразу прервать цикл. Тогда код будет выглядеть так

for ( int i = 1; i <= 10 ; i++)

{

if (i == 5)

{

System.out.println("Выход из цикла при значении i = " + i);

break;

}

System.out.println(i);

}

Как сделать правильно, по первому или второму варианту - зависит от поставленной задачи.

8. Можно прервать не весь цикл, как в примере в предыдущем пункте 7, а одну итерацию цикла с помощью ключевого слова continue.

Если рассматривать тот же пример, то конструкция будет следующей

for ( int i = 1; i <= 10 ; i++)

{

if (i == 5)

{

System.out.println("Прерываем итерацию при значении i = " + i);

continue;

}

System.out.println(i);

}

В данном случае на экран будут последовательно выведены значения переменной i от 1 до 4. Затем вместо 5 будет выведен текст "Прерываем итерацию при значении i = 5". Т.е. выполнение 5-й итерации будет прервано, число 5 не будет выведено на экран. Затем цикл продолжит своё выполнение с 6-й итерации и на экран будут последовательно выведены числа от 6 до 10.

Причём, если бы мы не стали выводить текст "Прерываем итерацию при значении i = 5" на экран, то 5-я итерация прервалась бы сразу. Тогда бы на экран были выведены цифры с 1 по 4, а затем с 6 по 10.

Итак, с теорией всё. Переходим к практике. Посмотрим, как выполнятся примеры из текущего урока.

Самый простой пример, наглядно демонстрирующий работу цикла for

for (int i = 1; i <= 10 ; i++)

{

System.out.println(i);

}

Конечный код для исполнения

Результат выполнения кода

-2

На экран выведены числа от 1 до 10.

Теперь пример с вложенными циклами.

-3

Результат выполнения:

-4

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

Теперь пример с двумя переменными и прерыванием цикла ключевым словом break.

-5

Результат выполнения:

-6

Здесь обращаем внимание на 2 момента:

  • Если бы не было ключевого слова break, то цикл бы работал до тех пор, пока значение переменной a не стало бы равно 100. Тогда он бы завершился не на 3-й итерации, а после выполнения 100-й.
  • Здесь значения переменной a начинают увеличиваться с 1. Поэтому по сути значение переменной a на каждой итерации совпадает с номером итерации.

Выводы:

  • Цикл - это набор команд, который выполняется с определённой периодичностью снова и снова до тех пор, пока соблюдается определённое условие. Как только условие перестаёт соблюдаться, цикл завершается и программа переходит к выполнению следующих команд.
  • Существуют несколько вариантов циклов. Цикл for - один из них.
  • Та часть кода, которая повторяется, называется телом цикла.
  • Одно выполнение тела цикла называется итерацией.
  • Наиболее распространенные варианты оператора счетчика - инкремент или декремент. Но возможны и другие варианты.
  • Необходимо следить за тем, чтобы не допустить ошибку неучтённой единицы и за тем, чтобы цикл не стал бесконечным.
  • В некоторых случаях используются конструкции с циклами, вложенными в другие циклы.
  • Работу цикла можно прервать с помощью ключевого слова break.
  • Работу одной итерации цикла можно прервать с помощью ключевого слова continue.

Ссылка на предыдущий урок

Ссылка на следующий урок

Ссылка на содержание курса