Nested loops
On This Lesson 11 topics
Lesson Overview
A single loop walks along a line: 1, 2, 3. Many problems are not lines but grids: rows and columns of a seating plan, a multiplication table, a calendar, a spreadsheet. To walk a grid you put a loop inside another loop. This is a nested loop.
On the track: the outer loop is the race day (heat 1, heat 2, heat 3), and the inner loop is the laps in each heat. For every heat, the runner completes all the laps before the next heat starts. The inner loop restarts from the beginning each time.
Why this matters: backend data is full of grids, such as rows with columns, groups with members, and days with time slots. Nested loops are also the first place where the cost of repetition grows noticeably, so counting how many times the body runs becomes an important habit.
This lesson builds on BEG-013-L01 to L04.
Learning Objectives
By the end of this lesson you will be able to:
- Write a loop inside another loop with clear names for the two counters.
- Explain that the inner loop runs completely for each outer iteration.
- Calculate how many times the inner body runs (outer count times inner count).
- Print rectangular grids and triangles.
- Make the inner loop depend on the outer counter.
- Say what
breakandcontinuedo inside a nested loop.
Written Explanation
The shape
for (int row = 1; row <= 3; row++) {
for (int col = 1; col <= 4; col++) {
// inner body
}
}The inner loop is part of the outer loop's body. Every time the outer loop starts an iteration, the inner loop starts again from its own start: col is created fresh, runs 1 to 4, and disappears.
Counting the runs
If the outer loop runs R times and the inner loop runs C times each time, the inner body runs R times C in total. For 3 rows and 4 columns that is 12. The outer body (everything outside the inner loop) runs only R times.
This is the key habit of the lesson: before running a nested loop, say the number out loud. For 5 rows by 6 columns the answer is 30. For 1,000 by 1,000 it is a million. Counting like this is the beginning of estimating cost, which BEG-039 develops.
Rows and columns
Use the outer loop for rows and the inner loop for columns. To print a row of stars on one line you use System.out.print inside the inner loop and a System.out.println() after it, still inside the outer loop:
for (int row = 1; row <= 3; row++) {
for (int col = 1; col <= 4; col++) {
System.out.print("* ");
}
System.out.println(); // end the row
}The println() is after the inner loop but inside the outer one. Move it and the output changes: that is the most common nested-loop bug.
Use meaningful, different names
Name the counters row and col (or day and slot), not i and i. If you reuse the same name in the inner loop, Java rejects it, because the outer variable is still in scope. Different names also make your trace tables easier.
The inner loop depends on the outer
The inner limit can use the outer counter. That produces triangles:
for (int row = 1; row <= 4; row++) {
for (int col = 1; col <= row; col++) {
System.out.print("*");
}
System.out.println();
}Row 1 prints one star, row 2 prints two, and so on. The inner body now runs 1 + 2 + 3 + 4 = 10 times, not 4 times 4, so the "multiply" rule is only for loops whose inner count does not change. When it does, add up the inner counts row by row.
Tracing a nested loop
Trace the triangle above with a table that has one row per inner iteration:
row | col values | Stars printed |
|---|---|---|
| 1 | 1 | 1 |
| 2 | 1, 2 | 2 |
| 3 | 1, 2, 3 | 3 |
| 4 | 1, 2, 3, 4 | 4 |
Read it from the top: row stays fixed while col runs through its whole list, then row moves on and col starts over. If you lose your place in a nested loop, this "outer fixed, inner sweeping" picture gets you back. A useful sanity check is to print row and col together inside the inner body, as in System.out.println(row + "," + col);, and compare the pairs with your table.
Why the inner counter restarts
The inner for header runs its start part every time the inner loop begins, so int col = 1 runs again for each new row. That is why the same inner code can print many identical rows. It also means the inner counter cannot carry information from one row to the next: if you need a total across all rows, declare it before both loops, as you did for a running total in L01.
break and continue in nested loops
As L04 said, they affect only the innermost loop. A break in the inner loop ends that row's inner loop; the outer loop then moves to the next row.
Examples
Example 1: a 3-by-4 grid with a count (simple)
int runs = 0;
for (int row = 1; row <= 3; row++) {
for (int col = 1; col <= 4; col++) {
System.out.print("* ");
runs++;
}
System.out.println();
}
System.out.println("runs=" + runs);Output:
* * * *
* * * *
* * * *
runs=12Three rows, four stars each, and the counter confirms 3 times 4.
Example 2: a small multiplication table (practical)
for (int row = 1; row <= 3; row++) {
for (int col = 1; col <= 3; col++) {
System.out.print(row * col + "\t");
}
System.out.println();
}Output (the code prints a tab character after each number; it is shown here as spaces):
1 2 3
2 4 6
3 6 9 Each cell is row * col. The same pattern with 9 by 9 gives the full table from the module's exercises, whose body runs 81 times.
Example 3: a cinema seating count with break (realistic)
A cinema has 3 rows of 4 seats. Booking software stops looking at a row once it reaches seat 3 (for this example, seats from 3 on are reserved). How many seats does it count?
int count = 0;
for (int row = 1; row <= 3; row++) {
for (int seat = 1; seat <= 4; seat++) {
if (seat == 3) break;
count++;
}
}
System.out.println("count=" + count);Output:
count=6In each row, seats 1 and 2 are counted and then break leaves the inner loop. The outer loop carries on to the next row, so we get 2 seats times 3 rows = 6. If break ended the outer loop too, the answer would be 2.
Backend Insight
Grids are everywhere in data: orders with line items, users with permissions, days with time slots. Nested loops are how you compare "each item with each other item" too, and that is where cost shows up:
- If you loop over 1,000 users and, for each, over 1,000 other users, the inner body runs a million times. At 100,000 users it is ten billion. A pattern that is fine for a demo can stall a server.
- When a nested loop looks slow, the first question is: "How many times does the body run?" Often one of the loops can be replaced by a smarter data structure, which later modules cover.
For now, build the instinct: each extra level of nesting multiplies the work. Three nested loops of 100 iterations each already run the body a million times.
Common Mistakes
Mistake 1: println() in the wrong place
- Incorrect:
System.out.println();inside the inner loop. Every star lands on its own line. - Correct: after the inner loop, still inside the outer one.
Mistake 2: Adding instead of multiplying
For a fixed 5 by 6 grid the body runs 30 times, not 11.
Mistake 3: Reusing the same counter name
for (int i = 1; i <= 3; i++) {
for (int i = 1; i <= 3; i++) { } // compile error: i already defined
}Mistake 4: Expecting break to leave both loops
Only the inner loop ends. Use a flag or a method with return to leave both.
Mistake 5: Forgetting the inner loop restarts
col starts again at 1 for every row. If you declare the inner counter outside the outer loop, it will not restart, and only the first row prints properly.
Exercises
Try each exercise yourself before opening the solutions.
Level A: Foundation
A1. How many times does the inner body run: outer 4 times, inner 5 times?
Show solution A1
A1. 20 (4 times 5).
A2. What does this print?
for (int r = 1; r <= 2; r++) {
for (int c = 1; c <= 3; c++) {
System.out.print("#");
}
System.out.println();
}Show solution A2
A2.
###
###A3. Why should the counters be called row and col rather than both i?
Show solution A3
A3. Java does not allow the same name for the inner variable while the outer one is in scope, and distinct names make the code and traces easier to read.
Level B: Application
B1. Print a rectangle of + characters with 4 rows and 7 columns.
Show solution B1
B1.
for (int r = 1; r <= 4; r++) {
for (int c = 1; c <= 7; c++) {
System.out.print("+");
}
System.out.println();
}B2. Print this triangle using the outer counter in the inner condition:
1
12
123
1234Show solution B2
B2.
for (int row = 1; row <= 4; row++) {
for (int col = 1; col <= row; col++) {
System.out.print(col);
}
System.out.println();
}B3. How many times does the inner body run in B2?
Show solution B3
B3. 1 + 2 + 3 + 4 = 10 times.
Level C: Challenge
C1. Print a 5 by 5 table where each cell shows row + col, with a space after each number. State how many times the body runs.
Show solution C1
C1.
for (int row = 1; row <= 5; row++) {
for (int col = 1; col <= 5; col++) {
System.out.print((row + col) + " ");
}
System.out.println();
}The body runs 25 times (5 times 5).
C2. Print a countdown triangle with 4 rows where row 1 has 4 stars and the last row has 1 star. Then say how many stars are printed in total.
Show solution C2
C2.
for (int row = 1; row <= 4; row++) {
for (int col = 1; col <= 5 - row; col++) {
System.out.print("*");
}
System.out.println();
}Row 1 has 4 stars, row 2 has 3, row 3 has 2, row 4 has 1: 4 + 3 + 2 + 1 = 10 stars.
Mini Challenge
Print a seat map for a small theatre: 4 rows labelled 1 to 4 and 6 seats per row. Each seat is shown as [ ], and each row ends with a new line.
Then make seat 2 in every row show [X] (taken) using an if inside the inner loop. At the end print the number of free seats.
Check your work: the map has 4 lines of 6 seats, the count of free seats is 20, and the inner body ran 24 times.
Summary & Next Lesson
Key takeaways
- A nested loop is a loop inside another; the inner loop restarts and finishes completely for every outer iteration.
- With fixed counts, the inner body runs outer times inner; with a changing inner count, add up the inner counts.
- Outer loop = rows, inner loop = columns; end each row with
println()after the inner loop. - Give the two counters different names.
breakandcontinueaffect only the innermost loop.
Next lesson
The next lesson, "Off-by-one errors and infinite loops", collects the two classic loop bugs and gives you a routine for catching them.
Self-check
- For 3 outer and 6 inner iterations, how many inner-body runs?
- Where does the
println()for a row belong? - What does
breakin the inner loop do to the outer loop? - Why does
for (int row...) { for (int row...) }fail to compile? - How many times does the inner body run if the inner loop runs
1..rowandrowgoes 1 to 3?
Show answers
- 18.
- After the inner loop and inside the outer loop.
- Nothing: the outer loop carries on with its next iteration.
- The inner
rowredeclares a variable that is still in scope. - 1 + 2 + 3 = 6 times.
References
- Oracle, The for Statement (Java Tutorials). It supports the scope of a loop variable, which is why the inner loop cannot reuse the outer name.
- Oracle, Branching Statements. It supports that an unlabeled
breakends only the innermost loop. - Examples 1 to 3 were compiled and run with JDK 21 (the table printed tab characters). The solutions for B2, C1, C2, and the mini challenge were checked by reasoning, not run. The rule that a redeclared variable is a compile error comes from the language rules and the scope description above; the exact compiler message was not captured.
Practice
Apply this lesson with the module's lab, exercises and quiz.
Marking a lesson complete is optional and you can undo it any time. Your progress stays in this browser.