Nested Loops in Java Explained — How They Work, When to Use Them, and Common Traps
Every real application deals with grid-like data — spreadsheets, game boards, image pixels, multiplication tables, seating charts, calendar grids. When your data has two dimensions, a single loop isn't enough. You need a loop inside a loop, and that's exactly what a nested loop gives you. Skip this concept and you'll hit a wall the moment you try to work with anything more complex than a flat list.
The problem a nested loop solves is simple: iterating over combinations. If you have 5 rows and 5 columns, you have 25 combinations to visit. Writing 25 individual lines of code is insane. One outer loop running 5 times, each containing an inner loop running 5 times, does the job cleanly and scales to any size without touching a single extra line.
By the end of this article you'll be able to write nested loops confidently, read someone else's nested loop and trace exactly what it does step by step, print patterns and grids, understand how the inner and outer loops relate to each other, and dodge the three mistakes that trip up almost every beginner the first time they encounter this concept.
What a Single Loop Does — The Foundation You Need First
Before nesting anything, make sure the single loop is crystal clear. A for loop in Java has three parts: a starting point, a condition that keeps it running, and a step that moves it forward. Each time the loop runs its body is called one iteration.
Think of a single loop as a DJ playing one playlist track by track. It starts at track 1, plays it, moves to track 2, plays it, and keeps going until the playlist ends. There is no concept of two playlists yet — that comes with nesting.
Here's a simple loop counting from 1 to 5. Read every line carefully, especially the inline comments — they show you exactly what Java is doing at each moment. Once this feels obvious to you, nested loops will feel like a natural next step rather than a scary jump.
public class SingleLoopDemo { public static void main(String[] args) { // This loop starts at rowNumber = 1 // It keeps running as long as rowNumber is 5 or less // After each iteration, rowNumber increases by 1 for (int rowNumber = 1; rowNumber <= 5; rowNumber++) { // This line runs ONCE per iteration System.out.println("Row number: " + rowNumber); } // Execution reaches here only AFTER the loop finishes completely System.out.println("Loop is done."); } }
Row number: 2
Row number: 3
Row number: 4
Row number: 5
Loop is done.
Your First Nested Loop — A Multiplication Table That Makes It Click
Now let's nest. A nested loop is just a loop placed inside another loop's body. The outer loop controls the 'big steps' (rows in our cinema analogy) and the inner loop does all the 'small steps' for each big step (seats in each row).
Here is the critical rule to burn into memory: the inner loop runs from start to finish completely every single time the outer loop takes one step. If the outer loop runs 3 times and the inner loop runs 4 times, the inner loop's body executes 3 × 4 = 12 times total.
The best way to see this is with a multiplication table — something your brain already knows the answer to, so you can verify the code is doing the right thing. We'll print a 5×5 multiplication table. Watch how the outer loop controls which row we're on, and the inner loop fills in every column for that row before we move on.
public class MultiplicationTable { public static void main(String[] args) { System.out.println("--- 5x5 Multiplication Table ---\n"); // Outer loop: controls the current ROW (1 through 5) for (int row = 1; row <= 5; row++) { // Inner loop: controls the current COLUMN (1 through 5) // This entire inner loop runs completely before row increases by 1 for (int column = 1; column <= 5; column++) { int product = row * column; // %-4d means: print an integer, left-padded to 4 characters wide // This keeps columns neatly aligned regardless of digit count System.out.printf("%-4d", product); } // After the inner loop finishes all 5 columns, move to a new line // This happens once per outer loop iteration (i.e., once per row) System.out.println(); } } }
1 2 3 4 5
2 4 6 8 10
3 6 9 12 15
4 8 12 16 20
5 10 15 20 25
Printing Star Patterns — The Classic Interview Test for Nested Loops
Star patterns are the 'Hello, World' of nested loops. Interviewers use them because printing a triangle or square forces you to understand exactly how the inner loop's range relates to the outer loop's current value — which is the deepest insight about nested loops.
In a simple pattern like a right-angle triangle, each row should print a number of stars equal to the current row number. Row 1 gets 1 star, Row 2 gets 2 stars, and so on. The trick is making the inner loop's upper limit equal to the outer loop's current variable.
This is the moment nesting goes from 'mechanical repetition' to 'dynamic control'. The inner loop isn't fixed at 5 columns anymore — it changes based on where the outer loop currently is. That relationship between the two loop variables is what unlocks complex patterns, 2D array traversal, and algorithm design.
public class StarPatterns { public static void main(String[] args) { int totalRows = 5; // ── Pattern 1: Right-angle triangle (growing) ── System.out.println("Pattern 1: Right-angle triangle"); for (int currentRow = 1; currentRow <= totalRows; currentRow++) { // Inner loop runs from 1 up to currentRow // When currentRow is 3, we print exactly 3 stars — dynamic! for (int starCount = 1; starCount <= currentRow; starCount++) { System.out.print("* "); } System.out.println(); // Move to next line after each row } System.out.println(); // Blank line between patterns // ── Pattern 2: Inverted triangle (shrinking) ── System.out.println("Pattern 2: Inverted triangle"); for (int currentRow = totalRows; currentRow >= 1; currentRow--) { // Now outer loop counts DOWN, inner loop still goes from 1 to currentRow // Row 5 prints 5 stars, Row 4 prints 4 stars, etc. for (int starCount = 1; starCount <= currentRow; starCount++) { System.out.print("* "); } System.out.println(); } System.out.println(); // ── Pattern 3: Solid square ── System.out.println("Pattern 3: Solid 5x5 square"); for (int currentRow = 1; currentRow <= totalRows; currentRow++) { // Inner loop always runs exactly totalRows times — a fixed square for (int currentColumn = 1; currentColumn <= totalRows; currentColumn++) { System.out.print("* "); } System.out.println(); } } }
*
* *
* * *
* * * *
* * * * *
Pattern 2: Inverted triangle
* * * * *
* * * *
* * *
* *
*
Pattern 3: Solid 5x5 square
* * * * *
* * * * *
* * * * *
* * * * *
* * * * *
Nested Loops with 2D Arrays — Where This Gets Genuinely Useful
Patterns are great for learning, but the real-world use case you'll hit constantly is 2D arrays — arrays that store data in rows and columns, like a spreadsheet or a game board. In Java, a 2D array is an array of arrays. To visit every single cell, you need exactly two nested loops: one for rows, one for columns.
Think of it like a spreadsheet. The outer loop moves you down through each row (row A, row B, row C...). For each row, the inner loop moves across every column (column 1, column 2, column 3...). Together they guarantee you visit every cell exactly once.
The example below creates a 3×4 seating chart grid (3 rows, 4 seats per row), fills it with seat numbers, and then prints it out in a readable format. This is the pattern used for everything from image processing to game boards to matrix math.
public class CinemaSeatingChart { public static void main(String[] args) { int totalRows = 3; int seatsPerRow = 4; // Declare a 2D array: 3 rows, 4 columns // Think of this as a grid with 3 rows of 4 seats each int[][] seatNumbers = new int[totalRows][seatsPerRow]; int seatCounter = 1; // ── Step 1: Fill the grid with seat numbers ── // Outer loop moves through each ROW of the array for (int row = 0; row < totalRows; row++) { // Inner loop moves through each COLUMN (seat) within the current row for (int seat = 0; seat < seatsPerRow; seat++) { // Assign a unique seat number to this position in the grid seatNumbers[row][seat] = seatCounter; seatCounter++; // Move to next seat number } } // ── Step 2: Print the seating chart ── System.out.println("=== Cinema Seating Chart ==="); System.out.println("Row\t| Seat 1\t| Seat 2\t| Seat 3\t| Seat 4"); System.out.println("--------|-----------|-----------|-----------|----------"); // Use nested loops again to READ the grid we just filled for (int row = 0; row < totalRows; row++) { // Print the row label (Row 1, Row 2, Row 3 — adding 1 so it's not zero-indexed) System.out.print("Row " + (row + 1) + "\t|"); for (int seat = 0; seat < seatsPerRow; seat++) { // Read and print the seat number at this [row][seat] position System.out.print(" Seat " + seatNumbers[row][seat] + "\t|"); } System.out.println(); // New line after all seats in the row are printed } System.out.println("\nTotal seats: " + (totalRows * seatsPerRow)); } }
Row | Seat 1 | Seat 2 | Seat 3 | Seat 4
--------|-----------|-----------|-----------|----------
Row 1 | Seat 1 | Seat 2 | Seat 3 | Seat 4 |
Row 2 | Seat 5 | Seat 6 | Seat 7 | Seat 8 |
Row 3 | Seat 9 | Seat 10 | Seat 11 | Seat 12 |
Total seats: 12
| Aspect | Single Loop | Nested Loop |
|---|---|---|
| Dimensions handled | 1D — flat list or sequence | 2D — grid, table, matrix |
| Typical use case | Iterating an array, counting, summing | 2D arrays, patterns, combinations |
| Number of iterations | n (where n = loop count) | outer × inner (e.g. 5×5 = 25) |
| Performance concern | Rarely an issue at small scale | Grows fast — 1000×1000 = 1,000,000 iterations |
| Variable interaction | Only one loop variable active | Inner loop can use outer loop's variable |
| Readability risk | Low — straightforward to follow | Medium — easy to lose track of which loop does what |
| Common real-world example | Printing a shopping list | Printing a multiplication table or game board |
🎯 Key Takeaways
- The inner loop runs completely from start to finish every single time the outer loop takes one step — burn this into memory because every nested loop question starts with understanding this relationship.
- Total iterations = outer loop count × inner loop count. A 5×5 nested loop runs 25 times total. A 1000×1000 nested loop runs 1,000,000 times — nested loops scale as O(n²), so always ask yourself if you really need them.
- When the inner loop's condition references the outer loop's variable (e.g.
starCount <= currentRow), the inner loop is dynamic — it does different amounts of work on each outer iteration. This is what enables patterns, triangles, and classic algorithms like Bubble Sort. - Put your newline (
System.out.println()) in the outer loop's body, after the inner loop — not inside the inner loop. This single placement rule is the difference between a properly formatted grid and a column of individual values.
⚠ Common Mistakes to Avoid
- ✕Mistake 1: Using the wrong loop variable inside the inner loop — Writing
row rowinstead ofrow columnin a multiplication table. The symptom is a diagonal pattern of correct values but wrong numbers everywhere else. Fix: clearly name your outer variable (e.g.row) and your inner variable (e.g.column) and double-check that each calculation uses the right one. Meaningless names likeiandjmake this mistake almost invisible. - ✕Mistake 2: Putting
System.out.println()(the newline) inside the inner loop instead of after it — The symptom is every single value printing on its own line instead of a whole row printing together before a line break. Fix: the newline that ends a row belongs in the OUTER loop's body, after the inner loop finishes. A quick rule: the inner loop fills one row; the outer loop decides when to end that row. - ✕Mistake 3: Using
<=instead of<when looping over a 2D array's length — This causes a runtime crash:ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 5. Fix: Java arrays are zero-indexed, so a 5-element array has valid indices 0, 1, 2, 3, 4. Your condition must becolumn < seatsPerRow(using strict less-than), nevercolumn <= seatsPerRow. Use.lengthon the array directly —column < seatNumbers[row].length— to make it bulletproof.
Interview Questions on This Topic
- QWhat is the total number of times the inner loop body executes if the outer loop runs 4 times and the inner loop runs 6 times? Walk me through why. (Expected answer: 24 times — 4 outer iterations × 6 inner iterations each. A strong candidate explains that the inner loop resets completely for each outer iteration.)
- QHow would you use nested loops to find if any two numbers in an array add up to a target sum? (This is the classic 'two-sum brute force' question. Expected approach: outer loop picks one number, inner loop picks every other number and checks if outer + inner equals the target. A strong candidate also mentions this is O(n²) and that a hash map solution is O(n).)
- QIf I have a nested loop where the outer runs 1,000 times and the inner runs 1,000 times, how many total operations is that — and why should I care? (Expected answer: 1,000,000 operations — O(n²) complexity. A great candidate explains that nested loops often signal quadratic time complexity, which becomes a serious performance problem at scale, and mentions that this is why interviewers pay close attention to nested loops during algorithm reviews.)
Frequently Asked Questions
How many loops can you nest in Java?
Java has no hard limit on how deep you can nest loops — you can have a loop inside a loop inside a loop (triple-nested) and so on. In practice, going beyond two levels of nesting is a red flag: your code becomes hard to read and the performance cost multiplies exponentially. If you find yourself writing triple-nested loops, it's almost always a sign to rethink your data structure or break the logic into a separate method.
Does the inner loop variable reset every time the outer loop iterates?
Yes, absolutely. The inner loop's initialization (e.g. int column = 1) runs fresh every time the outer loop's body starts a new iteration. So after the inner loop completes all its steps for row 1, it resets back to column = 1 for row 2. This reset is what makes it a loop rather than a single run — and it's the most important behaviour to understand when tracing nested loops.
Can I use a `while` loop as the inner or outer loop instead of a `for` loop?
Yes. You can mix and match any loop types — for, while, or do-while — as the inner or outer loop in any combination. The nesting behaviour is identical regardless of loop type. That said, for loops are the most common choice for nested loops when you know the number of iterations upfront, because all three parts (init, condition, step) are visible on one line, making it easier to track both loops at a glance.
Written and reviewed by senior developers with real-world experience across enterprise, startup and open-source projects. Every article on TheCodeForge is written to be clear, accurate and genuinely useful — not just SEO filler.