Этот урок получился большим, с большим количеством информации. Но я не могу не рассказать обо всех особенностях цикла 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);
}
Конечный код для исполнения
Результат выполнения кода
На экран выведены числа от 1 до 10.
Теперь пример с вложенными циклами.
Результат выполнения:
Из результата видно, что на первой итерации внешнего цикла выполняются три итерации внутреннего цикла, затем на второй итерации внешнего цикла выполняются три итерации внутреннего цикла. Ну и наконец на третьей итерации внешнего цикла выполняются три итерации внутреннего цикла.
Теперь пример с двумя переменными и прерыванием цикла ключевым словом break.
Результат выполнения:
Здесь обращаем внимание на 2 момента:
- Если бы не было ключевого слова break, то цикл бы работал до тех пор, пока значение переменной a не стало бы равно 100. Тогда он бы завершился не на 3-й итерации, а после выполнения 100-й.
- Здесь значения переменной a начинают увеличиваться с 1. Поэтому по сути значение переменной a на каждой итерации совпадает с номером итерации.
Выводы:
- Цикл - это набор команд, который выполняется с определённой периодичностью снова и снова до тех пор, пока соблюдается определённое условие. Как только условие перестаёт соблюдаться, цикл завершается и программа переходит к выполнению следующих команд.
- Существуют несколько вариантов циклов. Цикл for - один из них.
- Та часть кода, которая повторяется, называется телом цикла.
- Одно выполнение тела цикла называется итерацией.
- Наиболее распространенные варианты оператора счетчика - инкремент или декремент. Но возможны и другие варианты.
- Необходимо следить за тем, чтобы не допустить ошибку неучтённой единицы и за тем, чтобы цикл не стал бесконечным.
- В некоторых случаях используются конструкции с циклами, вложенными в другие циклы.
- Работу цикла можно прервать с помощью ключевого слова break.
- Работу одной итерации цикла можно прервать с помощью ключевого слова continue.
Ссылка на предыдущий урок
Ссылка на следующий урок
Ссылка на содержание курса