java-foundations Lesson 14 18 min read

Nested Loops

Loops inside loops — patterns, tables, and 2D traversal

Reading: Reges & Stepp: Ch. 2 §2.3, Ch. 5

After this lesson, you will be able to:

  • Explain how a nested loop executes: the inner loop completes all iterations for each single iteration of the outer
  • Trace nested loop execution using a table
  • Print rectangular and triangular patterns using nested for loops
  • Use System.out.print vs System.out.println to control row-based output
  • Identify and fix common nested loop mistakes

The Clock on the Wall

Think about a clock. The minute hand goes around 60 times for every single revolution of the hour hand. That is a nested loop. The hour hand is the outer loop (12 iterations per cycle), and the minute hand is the inner loop (60 iterations per cycle). For each hour, the minute hand completes a full sweep before the hour hand advances. In total, the minute hand ticks 12 x 60 = 720 times per full cycle.

Nested loops work exactly the same way. When you place one loop inside another, the inner loop runs to completion for every single iteration of the outer loop. This is the mechanism behind printing patterns, building tables, and processing two-dimensional data.


A Loop Inside a Loop

Here is the basic structure:

for (int outer = 0; outer < n; outer++) {
    // runs n times

    for (int inner = 0; inner < m; inner++) {
        // runs n * m times total
    }

    // also runs n times (after the inner loop finishes)
}

The execution order:

  1. Outer loop starts: outer = 0.
  2. Inner loop runs completely: inner = 0, 1, 2, ..., m-1.
  3. Outer loop advances: outer = 1.
  4. Inner loop runs completely again from scratch: inner = 0, 1, 2, ..., m-1.
  5. This repeats until the outer loop finishes.

Key Insight: The inner loop completely resets for each iteration of the outer loop. It does not remember where it left off. Every time the outer loop advances, the inner loop starts over from its initialization.

The mental model that makes this click: outer loop = rows, inner loop = columns. For each row, process every column.


From Python to Java

From CSCD 110: You may have used nested loops in Python to print patterns. Java’s nested loop structure is identical in logic — just more braces and explicit loop syntax:

Python Java
for i in range(3): for (int i = 0; i < 3; i++) {
    for j in range(4):     for (int j = 0; j < 4; j++) {
        print("*", end="")         System.out.print("*");
      }
    print()     System.out.println();
  }

Both print a 3-row, 4-column rectangle of stars. Python’s end="" to suppress the newline becomes Java’s System.out.print (no ln). Python’s bare print() for a newline becomes System.out.println().


Tracing Nested Loops

Tracing is even more critical for nested loops than for single loops. You must track both loop variables simultaneously. Here is a small example:

for (int i = 1; i <= 2; i++) {
    for (int j = 1; j <= 3; j++) {
        System.out.print(i + "," + j + "  ");
    }
    System.out.println();
}

Trace it step by step:

i j Output Notes
1 1 1,1 Inner loop starts
1 2 1,2  
1 3 1,3 Inner loop ends
1 (newline) println() after inner loop
2 1 2,1 Inner loop restarts from 1
2 2 2,2  
2 3 2,3 Inner loop ends
2 (newline) println() after inner loop

Output:

1,1  1,2  1,3
2,1  2,2  2,3

When i = 1, j cycles through 1, 2, 3 and then resets. When i advances to 2, j starts over at 1 again. The inner loop runs 3 iterations for each of the 2 outer iterations, giving 2 x 3 = 6 total prints.

The Trick: Always trace nested loops with small values first. Use n = 2 or n = 3. Write out every single step in a table. Once the pattern clicks with small values, it scales to any size.

Check Your Understanding
How many times does the inner System.out.print execute in the code above?
A 2 times
B 3 times
C 5 times
D 6 times
Answer: D. The outer loop runs 2 times (i = 1, 2). For each outer iteration, the inner loop runs 3 times (j = 1, 2, 3). Total: 2 x 3 = 6.

Printing Rectangular Patterns

The simplest nested loop application: print a rectangle of characters. The outer loop controls rows, and the inner loop controls columns.

void main() {
    int rows = 4;
    int cols = 5;

    for (int row = 0; row < rows; row++) {
        for (int col = 0; col < cols; col++) {
            System.out.print("*");
        }
        System.out.println();   // newline after each row
    }
}

Output:

*****
*****
*****
*****

The outer loop runs 4 times (one per row). For each row, the inner loop prints 5 stars using System.out.print (no newline). After the inner loop finishes one row, System.out.println() moves the cursor to the next line.

This is worth emphasizing because it trips people up:

Method What it does When to use it
System.out.print("*") Prints without a newline Inside the inner loop (building a row)
System.out.println() Prints a newline only After the inner loop (ending a row)

If you use println inside the inner loop, every star lands on its own line. If you forget println after the inner loop, all rows merge into one long line.

Common Pitfall: Forgetting the System.out.println() after the inner loop. Without it, all 20 stars print on a single line: ********************. The newline must be inside the outer loop but after the inner loop.


The Multiplication Table

Nested loops are the natural tool for building tables. Each row-column combination produces one cell value. Here is a complete multiplication table:

void main() {
    int size = 5;

    // Print header row
    System.out.print("  x |");
    for (int col = 1; col <= size; col++) {
        System.out.printf("%4d", col);
    }
    System.out.println();

    // Print separator
    System.out.print("----+");
    for (int col = 1; col <= size; col++) {
        System.out.print("----");
    }
    System.out.println();

    // Print table body (nested loop)
    for (int row = 1; row <= size; row++) {
        System.out.printf("%3d |", row);
        for (int col = 1; col <= size; col++) {
            System.out.printf("%4d", row * col);
        }
        System.out.println();
    }
}

Output:

  x |   1   2   3   4   5
----+--------------------
  1 |   1   2   3   4   5
  2 |   2   4   6   8  10
  3 |   3   6   9  12  15
  4 |   4   8  12  16  20
  5 |   5  10  15  20  25

Notice the use of System.out.printf("%4d", value) to format each number in a 4-character-wide column. This keeps the table aligned even when numbers have different digit counts. The nested loop in the table body runs 5 x 5 = 25 times — once for each cell.

Check Your Understanding
In the multiplication table code, what does row * col produce when row = 3 and col = 4?
A 7
B 12
C 34
D 15
Answer: B. The multiplication table prints the product of the current row and column. When row = 3 and col = 4, the value is 3 * 4 = 12. This is exactly what appears in row 3, column 4 of the output.

Triangle Patterns: Varying the Inner Loop Bound

A rectangle has a constant number of columns per row. A triangle changes the number of columns based on which row you are on. The key technique: make the inner loop’s condition depend on the outer loop variable.

Right Triangle

int n = 5;
for (int row = 1; row <= n; row++) {
    for (int col = 0; col < row; col++) {   // col < row, not col < n
        System.out.print("*");
    }
    System.out.println();
}

Output:

*
**
***
****
*****

Trace the inner loop’s behavior:

row Inner loop runs… Stars printed
1 col: 0 1 star
2 col: 0, 1 2 stars
3 col: 0, 1, 2 3 stars
4 col: 0, 1, 2, 3 4 stars
5 col: 0, 1, 2, 3, 4 5 stars

Total stars: 1 + 2 + 3 + 4 + 5 = 15.

Key Insight: When the inner loop’s bound depends on the outer loop variable (col < row), each row gets a different number of iterations. This is how you create triangular patterns instead of rectangular ones.

Inverted Triangle

Flip the triangle by reversing the relationship:

int n = 5;
for (int row = 1; row <= n; row++) {
    for (int col = 0; col < n - row + 1; col++) {
        System.out.print("*");
    }
    System.out.println();
}

Output:

*****
****
***
**
*

When row = 1, the inner loop runs 5 - 1 + 1 = 5 times. When row = 5, it runs 5 - 5 + 1 = 1 time. The formula n - row + 1 counts down as row counts up.

Number Triangle

Instead of printing the same character, use the column variable as the output:

int n = 5;
for (int row = 1; row <= n; row++) {
    for (int col = 1; col <= row; col++) {
        System.out.print(col + " ");
    }
    System.out.println();
}

Output:

1
1 2
1 2 3
1 2 3 4
1 2 3 4 5

The inner loop variable col does double duty: it controls how many numbers to print and provides the value to print.


Total Iterations: Counting the Work

Understanding how many times the inner body runs helps you reason about your program’s behavior:

Pattern Total iterations Example
Rectangle (n x m) n x m 4 rows x 5 cols = 20
Square (n x n) n^2 n = 10: 100
Right triangle n(n+1)/2 n = 5: 15

When both loops run n times, the total is n^2. Doubling n quadruples the work. This is the origin of O(n^2) time complexity that you will study in CSCD 300 (Data Structures), where sorting algorithms like bubble sort and selection sort use nested loops.


Common Mistakes

1. Reusing the Same Loop Variable

for (int i = 0; i < 5; i++) {
    for (int i = 0; i < 3; i++) {   // ERROR: i already defined
        System.out.print("*");
    }
}

Java will not compile this. Each loop needs its own variable name. Use i and j, or better yet, row and col.

2. Using the Wrong Variable

for (int row = 1; row <= n; row++) {
    for (int col = 0; col < row; col++) {
        System.out.print(row);   // Bug: prints the row number, not the column
    }
    System.out.println();
}

If you wanted to print 1 2 3 4 on row 4, you need col (or col + 1), not row. Mixing up which variable controls what is one of the most frequent nested loop bugs.

3. Mismatched Bounds

// Intended: triangle where row i has i stars
for (int row = 1; row <= n; row++) {
    for (int col = 0; col < n; col++) {   // Bug: col < n instead of col < row
        System.out.print("*");
    }
    System.out.println();
}

This prints a rectangle, not a triangle. The inner loop’s bound is n (constant) when it should be row (varying). Always ask: should the inner loop run the same number of times every row, or a different number?

4. Misplaced println

for (int row = 0; row < 3; row++) {
    for (int col = 0; col < 4; col++) {
        System.out.print("*");
        System.out.println();   // Bug: newline after EVERY star
    }
}

This prints each star on its own line instead of 4 stars per row. The println() belongs after the inner loop, not inside it.

Check Your Understanding
What does this code print?
for (int row = 1; row <= 3; row++) {
    for (int col = 1; col <= row; col++) {
        System.out.print(row);
    }
    System.out.println();
}
A 1 / 1 2 / 1 2 3 (number triangle)
B 1 / 22 / 333
C 1 / 2 / 3
D 123 / 123 / 123
Answer: B. The code prints row (not col) inside the inner loop. Row 1 prints "1" once. Row 2 prints "2" twice: "22". Row 3 prints "3" three times: "333". If you wanted the number triangle from option A, you would print col instead of row.

Variable Naming Conventions

Clear variable names prevent confusion when loops are nested:

Convention Best for
i, j Generic nested loops, math-heavy code
row, col Pattern printing, tables, grids
outer, inner When the relationship between loops matters more than the data

For this course, prefer row and col when printing patterns. They make the code self-documenting: you never have to wonder which variable controls rows and which controls columns.


Big Picture

Big Picture: Nested loops are everywhere in computing. In CSCD 211 (Programming Principles II), you will use nested loops to traverse 2D arrays. In CSCD 300 (Data Structures), sorting algorithms like bubble sort and selection sort use nested loops, and their O(n^2) runtime comes directly from the n x n iteration count. In CSCD 305 (Intro to Database Systems), a nested-loop join processes every combination of rows from two tables. The two-loop pattern you learn here scales to every domain.


Summary

Nested loops give you the power of two-dimensional repetition. The outer loop controls rows; the inner loop controls columns. The inner loop resets and runs to completion for every single iteration of the outer.

Rectangle: the inner loop bound is constant (same iterations every row).

Triangle: the inner loop bound depends on the outer variable (col < row), giving each row a different width.

Total work: outer iterations times inner iterations. For an n x n grid, that is n^2. For a triangle of height n, it is n(n+1)/2.

Output control: use System.out.print to build a row piece by piece, then System.out.println() after the inner loop to end the row.

Next up: Methods — how to package loops and logic into reusable, named blocks of code. Once you can write a pattern-printing nested loop, wrapping it in a method is the next natural step.