Цикл while в Java это оператор, который повторяет блок кода до тех пор, пока логическое условие остается истинным. Условие проверяется перед каждым проходом, поэтому тело цикла может не выполниться ни разу. У цикла есть вторая форма, do-while: она сначала выполняет тело и только потом проверяет условие, то есть гарантирует минимум один проход.

Кратко

  • while (условие) { ... } проверяет условие до каждого прохода, поэтому тело может не выполниться ни разу. Это цикл с предусловием.
  • do { ... } while (условие); проверяет условие после тела, поэтому тело выполняется минимум один раз. Это цикл с постусловием.
  • break немедленно выходит из цикла, continue пропускает остаток тела и возвращает управление к проверке условия.
  • while (true) это бесконечный цикл: выход из него организуют командой break по внешнему событию.
  • Циклы можно вкладывать друг в друга: внутренний цикл полностью отрабатывает на каждом шаге внешнего.
  • За изменением переменной из условия следит сам программист. Если в теле она не меняется, программа зависнет.

Введение

Наши самые первые программы представляли собой последовательность инструкций, которые выполняются одна за другой. Без развилок. Это и HelloWorld, выводящий в консоль фразу приветствия, арифметические вычисления. После первых программ мы научились ветвлению, то есть программа выполняла те или иные действия в зависимости от условий. Вот как можно было бы закодировать включение кондиционера на обогрев и охлаждение:

if (tempRoom>tempComfort)
    airConditionerOn();
if (tempRoom<tempComfort)
    heaterOn();
Сделаем следующий шаг. В быту мы часто выполняем однообразные повторяющиеся действия, например, чистим яблоки для пирога. Этот увлекательный процесс можно описать как:
  1. Если в тазике есть яблоки, то выполняем шаги с 1.1 по 1.4:

    1. 1.1. Берем яблоко
    2. 1.2. Чистим и нарезаем его дольками
    3. 1.3. Помещаем на основание пирога из теста на сковороде
    4. 1.4. Возвращаемся на шаг 1.
Яблочный пирог с наложенным поверх кодом цикла while, который уменьшает счетчик яблок cntApples до нуля
Допустим у вас 10 яблок, 2 руки и один нож. В жизни вы последовательно чистите весь десяток, руководствуясь одним и тем же алгоритмом. А как заставить программу делать повторяющееся действие с каждым яблоком?
  • Привяжем себя к числу яблок, но если у нас их мало, часть команд выполнялась бы вхолостую без «полезной нагрузки» (и, возможно, порезались, очищая кожуру несуществующего яблока).
  • Если яблок больше, чем наших команд обработки, часть продуктов пропала бы необработанной.
  • Подобный «код» тяжело читать, в нем много повторов, его трудно модифицировать.

Циклы: операторы многократного выполнения действий

Цикл while Java (цикл вайл) хорошо подойдет в нашем случае. Эта конструкция оформляет многократные действия в лаконичную и понятную структуру. Алгоритм по нарезке яблок для пирога в виде while в Java мог бы выглядеть как:

while(числоЯблокВТазике>0) {
    яблоко = тазик.взятьОчередноеЯблоко();
    положитьВПирог(яблоко.чистить().нарезать());
    числоЯблокВТазике--;//-- это декремент, уменьшает количество яблок на единицу
}
System.out.println("Яблоки для пирога обработаны.");

Синтаксис команды

Первый способ описания оператора while следующий:

while(Логическое выражение) {
	// Тело цикла - периодически выполняемые оператор(ы)
}
Выполняется следующим образом (по шагам):
  1. Вычисляем Логическое условие, следующее в скобках за while.
  2. Если логическое условие истинно, то выполняются операторы в теле цикла, после выполнения последнего оператора в теле цикла, переходим на шаг 1
  3. Если логическое условие ложно, то переходим к первому оператору за пределами цикла while.

Цикл с предусловием

Так как перед выполнением тела цикла мы всегда предварительно вычисляем логическое выражение (условие входа в цикл), то этот вид while часто называют циклом с предусловием. Построим таблицу первых десяти целых, положительных степеней числа. Шаг цикла задает инкремент power++:

public static void main(String[] args) {
    int number = 3; // Возводимое в степень число
    int result = 1; // Результат возведения в степень
    int power = 1; // Начальный показатель степени
    while(power <= 10) { // условие входа в цикл
        result = result * number;
        System.out.println(number + " в степени " + power + " = " + result);
        power++;
    }
}
Результат вывода на консоль:

3 в степени 1 = 3
3 в степени 2 = 9
3 в степени 3 = 27
3 в степени 4 = 81
3 в степени 5 = 243
3 в степени 6 = 729
3 в степени 7 = 2187
3 в степени 8 = 6561
3 в степени 9 = 19683
3 в степени 10 = 59049
Process finished with exit code 0

Цикл с постусловием

Второй вид цикла:

do {
    // Тело цикла - периодически выполняемые оператор(ы)
}while (Логическое выражение);
Выполняется следующим образом (шаги):
  1. Выполняется тело цикла (сразу после ключевого слова do).
  2. Вычисляем Логическое условие, следующее в скобках за while.
  3. Если логическое условие истинно, то переходим на шаг 1
  4. Если логическое условие ложно, то переходим к первому оператору за пределами цикла while.
Два основных отличия от предыдущего вида цикла: тело цикла как минимум выполняется один раз и логическое условие проверяется после выполнения тела цикла. Поэтому этот вид цикла while называют циклом с постусловием. На этот раз выведем таблицу степеней числа, не превышающую 10000:

public static void main(String[] args) {
    int number = 3;// Возводимое в степень число
    int result = number;// Результат возведения в степень
    int power = 1;// Начальный показатель степени
    do {
        System.out.println(number + " в степени " + power + " = " + result);
        power++;
        result = result * number;
    }while (result < 10000); // условие выхода из цикла
}
Результат вывода на консоль:

3 в степени 1 = 3
3 в степени 2 = 9
3 в степени 3 = 27
3 в степени 4 = 81
3 в степени 5 = 243
3 в степени 6 = 729
3 в степени 7 = 2187
3 в степени 8 = 6561
Process finished with exit code 0
Обратите внимание на изменения в коде, сравнив с вариантом цикла с предусловием.

while, do-while и for: чем отличаются

Три оператора цикла решают одну задачу, но удобны в разных ситуациях:
ОператорКогда проверяется условиеСколько раз выполнится телоТипичная задача
whileдо тела циклаот 0 разчисло повторов заранее неизвестно: чтение до конца файла, ожидание события
do-whileпосле тела циклаот 1 разадействие нужно выполнить хотя бы раз: запросить ввод и проверить его
forдо тела цикла, счетчик объявлен в заголовкеот 0 разчисло повторов известно: перебор массива или коллекции по индексу
Внешне операторы разные, но устроены они одинаково: любой цикл for можно записать через while, вынеся объявление счетчика перед циклом, а его увеличение в конец тела.

Интересные факты о работе с циклами

Управляющие команды в теле цикла

Существуют две команды, влияющие на ход выполнения цикла: break, особенности применения которого мы покажем в следующей главе, и continue.
  • continue: прекращает выполнение тела текущего цикла и осуществляет переход к логическому выражению оператора while. Если вычисленное выражение будет истинно, выполнение цикла будет продолжено.
  • break: немедленно прекращает выполнение текущего цикла и осуществляет переход к первой команде за его пределами. Таким образом, выполнение текущего цикла прерывается. Подробнее мы рассмотрим ее в следующей теме.
Вспомним про наш фруктовый пример. Если мы не уверены в качестве предложенных яблок, то могли бы изменить код с применением команды continue:

while(числоЯблокВТазике>0) {
    яблоко = тазик.взятьОчередноеЯблоко();
    числоЯблокВТазике--;//-- это декремент, уменьшает количество яблок на единицу
    if (яблоко.плохое()) {  // метод вернет true для гнилого и т.п. яблока
        яблоко.выкинутьВМусор();
        continue; // продолжим цикл, перейдем к условию числоЯблокВТазике>0
    }
    положитьВПирог(яблоко.чистить().нарезать());
}
Конструкцию continue часто применяют, когда в теле цикла необходимо выполнять команды при наступлении некоторого условия, например, выполнить действия при срабатывании датчика в оборудовании (а иначе просто продолжить цикл считывания его показателей) или вычислить выражение только на определенных шагах цикла. Пример для последнего случая: вычисление в цикле while суммы кубов натуральных чисел, у которых квадрат больше их количества. Числа с меньшим квадратом код пропускает через continue:

public static void main(String[] args) {
    int sum = 0;    // итоговая сумма
    int i = 0;      // стартовое число ряда
    int count = 20; // количество чисел
    while(i<=count) {
        i++;        // берем очередное число, i++ эквивалентно i=i+1
        if (i*i<=count)  // если квадрат числа меньше
            continue;   // количества чисел - сумму не считаем
                        // переходим к следующему числу в цикле
        sum += i*i*i; // иначе считаем сумму кубов чисел
    } // sum += i*i*i - форма записи, аналогичная sum = sum + i*i*i
    System.out.println(sum);// печатаем результат
}

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

Данные управляющие команды чаще всего находят применение в бесконечном цикле. Его так называют, потому что логическое условие выхода никогда не выполняется. В коде он выглядит примерно как:

while(true) {
    // Тело цикла 
}
В этом случае и пригодится применение команды break для организации выхода из него. Этот вид цикла имеет место при ожидании внешних условий, которые формируются за пределами логики тела цикла. Например, в играх, эмулирующих виртуальный мир вокруг героя (выход из цикла = выход из игры), операционных системах. Или при использовании алгоритмов, возможно, улучшающих результат с каждым последующим вызовом в цикле, но ограничивая их по времени или наступлению внешнего события (шашки, шахматы или предсказание погоды). Следует помнить, что в обычных условиях бесконечные циклы это одна из проблем неустойчивости программы. Для демонстрации вернемся к степеням числа:

public static void main(String[] args) {
    int number = 3; // Возводимое в степень число
    int result = 1; // Результат возведения в степень
    int power = 1; // Начальный показатель степени
    while(true) {
        result = result * number;
        System.out.println(number + " в степени " + power + " = " + result);
        power++;
        if (power>10)
            break; // выход из цикла
    }
}
Результат вывода на консоль:

3 в степени 1 = 3
3 в степени 2 = 9
3 в степени 3 = 27
3 в степени 4 = 81
3 в степени 5 = 243
3 в степени 6 = 729
3 в степени 7 = 2187
3 в степени 8 = 6561
3 в степени 9 = 19683
3 в степени 10 = 59049
Process finished with exit code 0

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

Вот мы и подошли к завершающей теме о наших циклах. Вспомним о яблочном пироге (надеюсь, вы не голодны в данный момент) и наш «цикл»:
  1. Если в тазике есть яблоки, выполняем шаги с 1.1 по 1.4:

    1. 1.1. Берем яблоко
    2. 1.2. Чистим и нарезаем его дольками
    3. 1.3. Помещаем на основание пирога из теста на сковороде
    4. 1.4. Возвращаемся на шаг 1.
Подробнее распишем процесс нарезания дольками:
  1. Число долек = 0
  2. Пока число долек < 12, выполнить шаги с 2.1 по 2.3

    1. 2.1. Отрезать очередную дольку от яблока
    2. 2.2. Кол-во долек ++
    3. 2.3. Возвращаемся на шаг 2
И вставим в наш кондитерский алгоритм:
  1. Если в тазике есть яблоки, то выполняем шаги с 1.1 по 1.6:

    1. 1.1. Берем яблоко
    2. 1.2. Очищаем его от кожуры
    3. 1.3. Число долек = 0
    4. 1.4. Пока число долек < 12, выполнить шаги с 1.4.1 по 1.4.3
      1. 1.4.1. Отрезать очередную дольку от яблока
      2. 1.4.2. Кол-во долек ++
      3. 1.4.3. Возвращаемся на шаг 1.4
    5. 1.5. Помещаем дольки на основание пирога из теста на сковороде
    6. 1.6. Возвращаемся на шаг 1.
Получили цикл в цикле. Подобные конструкции весьма частые. Для завершающего примера построим таблицу умножения, которую школьники 90-х видели на обложках тетрадей в младших классах. В коде пригодятся обе формы вывода, System.out.print и System.out.println: первая оставляет курсор в той же строке, вторая переводит вывод на новую.
Таблица Пифагора с обложки школьной тетради: множители от 2 до 9 и их произведения

 public static void main(String[] args) {
    // Выводим значения второго множителя в строке
    System.out.println("    2  3  4  5  6  7  8  9"); 
    int i = 2;      // первый множитель, присваиваем стартовое значение
    while(i<10) {   // Первый цикл, выполняем пока первый множитель меньше 10
        System.out.print(i + " | ");// Выводим первый множитель в начало строки
        int j = 2;                  // второй множитель, стартовое значение
        while (j<10) { // Второй цикл, выполняем пока второй множитель меньше 10
            int mul=i*j; // Считаем произведение множителей
            if (mul<10)  // Если содержит одну цифру-после него выводим два пробела
                System.out.print(mul + "  ");
            else   // иначе выводим произведение и после него - один пробел
                System.out.print(mul + " ");
            j++;     // Увеличиваем на единицу второй множитель,
        }            // Переходим к началу второго цикла (while (j<10 ).... )
        System.out.println(); // Перейдем на следующую строку вывода
        i++;                  // Увеличиваем на единицу первый множитель,
    }                         // Перейдем к началу первого цикла (while ( i<10 ) ....
}
Результат вывода на консоль:

     2  3  4  5  6  7  8  9
2 | 4 6 8 10 12 14 16 18
3 | 6 9 12 15 18 21 24 27
4 | 8 12 16 20 24 28 32 36
5 | 10 15 20 25 30 35 40 45
6 | 12 18 24 30 36 42 48 54
7 | 14 21 28 35 42 49 56 63
8 | 16 24 32 40 48 56 64 72
9 | 18 27 36 45 54 63 72 81
Process finished with exit code 0
Циклы (в частности, оператор while) это один из фундаментальных кирпичиков построения программ. Решая задачи на JavaRush, вы изучите все их разнообразие, разберете тонкости функционирования и получите практические навыки их применения.

Вопросы и ответы

Чем цикл while отличается от do-while?

while проверяет условие перед выполнением тела, поэтому при ложном условии тело не выполнится ни разу. do-while проверяет условие после тела, поэтому тело всегда выполняется минимум один раз.

Когда использовать while, а когда for?

while удобен, когда число повторов заранее неизвестно: чтение строк до конца файла, ожидание события, работа до получения нужного результата. for удобен, когда число повторов известно или идет перебор массива по индексу.

Как выйти из бесконечного цикла while (true)?

Командой break внутри тела цикла: она немедленно передает управление первой команде за циклом. Обычно break ставят под проверку внешнего условия, например достижения нужного значения или сигнала на завершение работы.

Почему цикл while не выполняется ни разу?

Условие оказалось ложным уже при первой проверке. Проверьте начальные значения переменных и знак сравнения. Если тело обязано отработать хотя бы раз, возьмите do-while.

Чем continue отличается от break?

continue прерывает только текущий проход и возвращает управление к проверке условия, цикл продолжается. break прерывает весь цикл и передает управление первой команде за его пределами.

Почему программа зависает на цикле while?

Переменная из условия не меняется в теле цикла, поэтому условие остается истинным всегда. В while за изменением счетчика следит сам программист: убедитесь, что в теле есть шаг вроде power++ или count--. Источник: Oracle Java Tutorials: The while and do-while Statements.

Читайте также