1. Вступ
Почнімо із запитання: навіщо взагалі вкладати один цикл у інший? Річ у тім, що часто наші дані чи завдання структуровані не просто в один ряд, а, наприклад, у таблицю, сітку або навіть у багатовимірну структуру. Припустімо, ви хочете вивести на екран таблицю множення, перебрати двовимірний масив або пройти всі пари елементів. Тут одного циклу явно не вистачить — потрібен цикл у циклі.
У програмуванні вкладений цикл — це як два будильники: зовнішній починає «дзвонити», а всередині нього запускається ще один, який працюватиме щоразу, поки перший активний. Тож поки триває одна «зовнішня» ітерація, внутрішня проходить увесь свій цикл (і робить це знову й знову для кожної ітерації зовнішнього циклу).
Гарний приклад — години та хвилини. Години — це зовнішній цикл від 0 до 23, хвилини — внутрішній цикл від 0 до 59. На кожну зміну зовнішнього циклу внутрішній встигає пройти всі свої значення.
2. Синтаксис вкладених циклів
У Java синтаксис вкладених циклів нічим не відрізняється від звичайних — ви просто пишете один цикл всередині тіла іншого. Розгляньмо приклади з for і while:
// Зовнішній цикл for
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++) // Внутрішній цикл for
{
System.out.print(i + "," + j + " ");
}
System.out.println(); // Після внутрішнього циклу — перехід на новий рядок
}
Тут зовнішній цикл контролює змінну i (від 0 до 2), а внутрішній — змінну j (від 0 до 3). Для кожного значення i внутрішній цикл повністю проходить від j == 0 до j == 3. Якщо виконаєте цей код, побачите охайну таблицю координат:
0,0 0,1 0,2 0,3
1,0 1,1 1,2 1,3
2,0 2,1 2,2 2,3
Аналогічний приклад із використанням while:
int i = 0;
while (i < 3)
{
int j = 0;
while (j < 4)
{
System.out.print(i + "," + j + " ");
j++;
}
System.out.println();
i++;
}
Зверніть увагу: під час кожної ітерації зовнішнього циклу змінну внутрішнього циклу (j) потрібно ініціалізувати наново, інакше побачите лише один рядок!
3. Приклади роботи вкладених циклів
Приклад 1: виведення шахівниці (8×8)
Нехай перше завдання — вивести на екран класичну шахівницю у вигляді чорних і білих клітинок (позначимо: «#» — чорна, «_» — біла). Реалізуємо це за допомогою вкладених циклів for:
for (int row = 0; row < 8; row++)
{
for (int col = 0; col < 8; col++)
{
// Якщо сума індексів рядка та стовпця парна — клітинка біла, інакше чорна
if ((row + col) % 2 == 0)
System.out.print("_");
else
System.out.print("#");
}
System.out.println(); // Після кожного рядка — перехід на новий рядок
}
Результат:
_#_#_#_#
#_#_#_#_
_#_#_#_#
#_#_#_#_
_#_#_#_#
#_#_#_#_
_#_#_#_#
#_#_#_#_
Важливий момент: вкладеність гарантує, що для кожного рядка (row) ми повністю проходимо всі стовпці (col). Без вкладеності ми б не отримали структуру шахівниці — лише один рядок або один стовпець.
Приклад 2: таблиця множення
Один із класичних прикладів для вкладених циклів. Виведімо таблицю множення 1–9:
for (int i = 1; i <= 9; i++)
{
for (int j = 1; j <= 9; j++)
{
System.out.print(i * j + "\t");
}
System.out.println();
}
Форматування i * j + "\t" додає символ табуляції, щоб таблиця виглядала охайно.
Результат:
1 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
...
9 18 27 36 45 54 63 72 81
4. Вкладені цикли й керування ними — нюанси
Про вплив break і continue у вкладених циклах
Саме тут багато новачків роблять помилку. Якщо ви використовуєте break або continue у внутрішньому циклі, вони впливають лише на цей цикл. Зовнішній цикл продовжує роботу без змін.
Приклад: достроковий вихід лише з внутрішнього циклу
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 5; j++)
{
if (j == 3)
break; // вихід лише з внутрішнього циклу
System.out.print(i + "," + j + " ");
}
System.out.println();
}
Результат:
0,0 0,1 0,2
1,0 1,1 1,2
2,0 2,1 2,2
Якщо треба вийти одразу з двох вкладених циклів (наприклад, терміново завершити пошук при першому успішному збігу в таблиці), зазвичай використовують прапорець або спеціальний прийом (наприклад, return — якщо все відбувається всередині методу).
5. Візуалізація вкладених циклів
Іноді буває складно «побачити» послідовність виконання вкладених циклів. Розгляньмо таку блок‑схему:
У табличній формі: скільки загалом ітерацій буде виконано за i від 1 до 3, j від 1 до 4?
| i | j (перебирається для кожного i) | Ітерацій внутрішнього циклу |
|---|---|---|
| 1 | 1, 2, 3, 4 | 4 |
| 2 | 1, 2, 3, 4 | 4 |
| 3 | 1, 2, 3, 4 | 4 |
| Усього: 3 × 4 = 12 |
6. Помилки й підводні камені під час роботи з вкладеними циклами
Поширена помилка — некоректна ініціалізація змінної внутрішнього циклу. Наприклад, оголосити її поза зовнішнім циклом і не скидати її щоразу. У результаті внутрішній цикл може взагалі не виконуватися або виконуватися неправильно.
int j = 0;
for (int i = 0; i < 3; i++)
{
while (j < 4) // Увага: після першої ітерації j уже міг дорівнювати 4.
{
System.out.print(i + "," + j + " ");
j++;
}
System.out.println();
}
Тут цикл виконається лише один раз. Не забувайте ініціалізувати змінні внутрішніх циклів всередині зовнішніх!
Якщо випадково написати два вкладені цикли з однаковими змінними (for (int i = 0; ...) { for (int i = 0; ...) { ... } }), компілятор повідомить про помилку: змінну вже оголошено.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ