Java Tutorial
šŸ”

Java Nested Loops

Java Nested Loops

A nested loop is a loop placed inside the body of another loop. The inner loop completes all its iterations for every single iteration of the outer loop. That multiplication of iterations is both the power and the risk of nested loops — understanding what happens to execution count as the input grows is what separates developers who use nested loops correctly from those who introduce O(n²) problems where O(n) was achievable.

What Are Nested Loops in Java?

When you need to work with two-dimensional data — a grid, a matrix, a table, or combinations of two sets — nested loops express that naturally. The outer loop moves through rows (or the first dimension), and the inner loop processes each column (or the second dimension) for every row the outer loop visits.

Any loop type can be nested inside any other — for inside while, while inside for, for-each inside for. The choice of loop type at each level follows the same rules as single loops: use for when the count is known, while when it depends on runtime state, for-each when you need each element without an index.

Syntax

Basic Nested for Loop

for (int outer = 0; outer < outerLimit; outer++) { for (int inner = 0; inner < innerLimit; inner++) { // executes outerLimit Ɨ innerLimit times total } }

Nested for-each

for (ElementType outerElement : outerCollection) { for (ElementType innerElement : innerCollection) { // process each combination of outerElement and innerElement } }

Mixed — for inside while

while (outerCondition) { for (int inner = 0; inner < limit; inner++) { // inner loop count is fixed; outer termination depends on runtime state } }

The iteration count of a two-level nested loop is the product of both loop counts. A nested loop where the outer runs 100 times and the inner runs 100 times executes 10,000 iterations — O(n²) when both limits scale with the same input size. This is the first thing to check during any code review involving nested loops.

Beginner Examples

Multiplication Table

The classic two-dimensional output problem — each cell is the product of its row and column position.

public class MultiplicationTableDemo { public static void main(String[] args) { int tableSize = 5; for (int row = 1; row <= tableSize; row++) { for (int col = 1; col <= tableSize; col++) { // printf pads each product to 4 characters to align columns System.out.printf("%4d", row * col); } // Move to next line after each complete row System.out.println(); } } }
Output:
   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

The outer loop runs 5 times. For each outer iteration, the inner loop runs 5 times. Total iterations: 25. The inner loop's index col resets to 1 on every new outer iteration — that reset is fundamental to how nested loops produce two-dimensional output.

Triangle Pattern

Pattern printing is a common interview exercise because it tests whether the candidate understands how the inner loop's range can depend on the outer loop's current value.

public class TrianglePatternDemo { public static void main(String[] args) { int rows = 5; for (int row = 1; row <= rows; row++) { // Inner loop limit changes with each outer iteration // Row 1 prints 1 star, row 2 prints 2 stars, etc. for (int star = 1; star <= row; star++) { System.out.print("* "); } System.out.println(); } } }
Output:
* 
* * 
* * * 
* * * * 
* * * * * 

The inner loop limit is star <= row — it grows with the outer counter. This is the key insight in pattern programs: the inner loop does not need a fixed upper bound; it can depend on the outer loop variable. Total iterations here are 1 + 2 + 3 + 4 + 5 = 15, not 25 — this is O(n²/2) which is still O(n²) asymptotically.

Finding Pairs That Sum to a Target

This is where nested loops appear in real algorithmic problem-solving — checking every pair of elements from an array.

public class PairSumDemo { public static void main(String[] args) { int[] prices = {150, 300, 450, 200, 350}; int targetBudget = 500; System.out.println("Item pairs within budget of Rs. " + targetBudget + ":"); // Outer starts at 0, inner starts at outer+1 to avoid duplicate pairs for (int first = 0; first < prices.length; first++) { for (int second = first + 1; second < prices.length; second++) { int combined = prices[first] + prices[second]; if (combined <= targetBudget) { System.out.println(" Rs." + prices[first] + " + Rs." + prices[second] + " = Rs." + combined); } } } } }
Output:
Item pairs within budget of Rs. 500:
  Rs.150 + Rs.300 = Rs.450
  Rs.150 + Rs.200 = Rs.350
  Rs.150 + Rs.350 = Rs.500
  Rs.300 + Rs.200 = Rs.500

Starting the inner loop at first + 1 avoids checking (A, B) and then (B, A) — they are the same pair. This halves the work compared to starting at 0. This pattern is the two-pointer or brute-force pair approach that appears frequently in interview problems.

How Nested Loops Work Internally

Execution Flow

The diagram below shows how the JVM processes a two-level nested loop across three outer and three inner iterations.

Outer iteration 1:
  Inner iteration 1 → body runs
  Inner iteration 2 → body runs
  Inner iteration 3 → body runs (inner exits)

Outer iteration 2:
  Inner resets to 0
  Inner iteration 1 → body runs
  Inner iteration 2 → body runs
  Inner iteration 3 → body runs (inner exits)

Outer iteration 3:
  Inner resets to 0
  Inner iteration 1 → body runs
  Inner iteration 2 → body runs
  Inner iteration 3 → body runs (inner exits, outer exits)

Total body executions: 3 Ɨ 3 = 9

Every time the outer loop advances one step, the inner loop runs completely from its initial value to its exit condition. The inner loop variable resets independently of the outer loop variable on every outer iteration.

Time Complexity Impact

public class ComplexityDemo { public static void main(String[] args) { int inputSize = 100; long singleLoopCount = 0; long nestedLoopCount = 0; // Single loop — O(n) for (int i = 0; i < inputSize; i++) { singleLoopCount++; } // Nested loop — O(n²) for (int i = 0; i < inputSize; i++) { for (int j = 0; j < inputSize; j++) { nestedLoopCount++; } } System.out.println("Input size : " + inputSize); System.out.println("Single loop runs : " + singleLoopCount); System.out.println("Nested loop runs : " + nestedLoopCount); System.out.println("Ratio : " + (nestedLoopCount / singleLoopCount) + "x"); } }
Output:
Input size       : 100
Single loop runs : 100
Nested loop runs : 10000
Ratio            : 100x

At n=100, the nested loop executes 100 times more than the single loop. At n=1000, it executes 1000 times more. This quadratic growth is why nested loops over large datasets — product catalog comparisons, user-recommendation matrix generation, naive string matching — become severe performance problems in production. A two-level nested loop is only acceptable when either the inner or outer iteration count is provably small and bounded.

Basic Example

Summing every element in a 2D grid is a simple, direct use of nested loops: the outer loop walks each row, and the inner loop walks each column within that row.

public class Main { public static void main(String[] args) { int[][] grid = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} }; int total = 0; for (int row = 0; row < grid.length; row++) { for (int col = 0; col < grid[row].length; col++) { total += grid[row][col]; } } System.out.println("Sum of all elements: " + total); } }

Output

Sum of all elements: 45

How it works:

  1. ›The outer loop advances row from 0 to 2, once for each row in grid.
  2. ›For every single value of row, the inner loop runs completely — advancing col from 0 to 2 — adding each cell grid[row][col] to total.
  3. ›The inner loop resets to col = 0 at the start of each new outer iteration, so all 9 cells (3 rows Ɨ 3 columns) are visited exactly once.
  4. ›After both loops finish, total holds the sum of every element: 1+2+3+4+5+6+7+8+9 = 45.

Using break and Labels in Nested Loops

Breaking the Inner Loop Only

public class InnerBreakDemo { public static void main(String[] args) { for (int batch = 1; batch <= 3; batch++) { System.out.print("Batch " + batch + ": "); for (int item = 1; item <= 5; item++) { if (item == 3) { // Exits inner loop only — outer loop continues break; } System.out.print(item + " "); } System.out.println(); } } }
Output:
Batch 1: 1 2 
Batch 2: 1 2 
Batch 3: 1 2 

break without a label exits only the innermost loop. The outer loop continues normally. Each batch still processes items 1 and 2 before hitting the break at item 3.

Breaking the Outer Loop Using a Label

When a match is found in a nested search and the entire search must stop — not just the inner pass — a labeled break exits the outer loop directly.

public class LabeledBreakDemo { public static void main(String[] args) { int[][] salesGrid = { {120, 340, 890}, {210, 550, 100}, {670, 430, 820} }; int targetSales = 550; boolean found = false; // Label on the outer loop outerSearch: for (int region = 0; region < salesGrid.length; region++) { for (int quarter = 0; quarter < salesGrid[region].length; quarter++) { if (salesGrid[region][quarter] == targetSales) { System.out.println("Target Rs." + targetSales + "k found at:" + " Region " + region + ", Quarter " + (quarter + 1)); found = true; break outerSearch; // exits both loops immediately } } } if (!found) { System.out.println("Target not found in any region."); } } }
Output:
Target Rs.550k found at: Region 1, Quarter 2

Without break outerSearch, the inner break would only exit the inner loop and the outer loop would continue scanning the remaining regions unnecessarily. Labels are the only way to exit an outer loop from within an inner one in Java.

Best Practices

Keep nesting depth to two levels maximum

Three or more levels of nesting — a loop inside a loop inside a loop — produces code that is exponentially harder to read and reason about. When three levels feel necessary, extract the inner two levels into a private method. The calling code stays clean; the inner logic becomes independently testable.

Always check whether an O(n²) solution is acceptable for your data size

Before writing a nested loop over a collection, ask: what is the maximum size of the outer and inner collections? A nested loop over two collections of 100 items runs 10,000 iterations. Over 10,000 items, it runs 100 million iterations. For large datasets, consider whether a HashMap lookup can replace the inner loop — reducing O(n²) to O(n).

Break out of inner loops as soon as a result is found

If the inner loop is searching for a match, add break the moment the match is found. Continuing to scan after a result is already known wastes CPU time proportionally to how early in the dataset the match appears.

Give outer and inner loop variables meaningful names

Single-letter loop counters like i and j are conventional, but in nested loops they become ambiguous at a glance. Using rowIndex and colIndex, or regionIndex and quarterIndex, makes the purpose of each level clear without requiring comments.

Common Mistakes

Mistake 1 — Using the Same Loop Variable Name at Both Levels

// This is a compile-time error — 'i' is already declared in the enclosing scope for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) { // 'i' is already defined — compiler rejects this System.out.println(i); } }

Java requires each loop variable in a nested structure to have a unique name within its scope. Using the same name at two levels is a compile-time error. Using names like outerIndex and innerIndex avoids this entirely and adds clarity.

Mistake 2 — Off-by-One in the Inner Loop Bound

public class InnerOffByOneDemo { public static void main(String[] args) { String[] teams = {"Alpha", "Beta", "Gamma"}; String[] projects = {"Phoenix", "Atlas", "Nova"}; // Inner loop uses <= instead of < — accesses index 3, which does not exist try { for (int t = 0; t < teams.length; t++) { for (int p = 0; p <= projects.length; p++) { System.out.println(teams[t] + " → " + projects[p]); } } } catch (ArrayIndexOutOfBoundsException ex) { System.out.println("ArrayIndexOutOfBoundsException at inner index: " + projects.length); } } }
Output:
Alpha → Phoenix
Alpha → Atlas
Alpha → Nova
ArrayIndexOutOfBoundsException at inner index: 3

The inner loop's <= allows p to reach 3 on a zero-indexed array of length 3. The valid range is 0 through 2. The rule is always < array.length for zero-indexed iteration. This mistake is more common in nested loops because the inner bound is visually farther from the array declaration.

Mistake 3 — Unintentional O(n²) Over Large Data

import java.util.List; import java.util.ArrayList; public class QuadraticMistakeDemo { public static void main(String[] args) { // Simulating a large product catalog and a large wishlist List<String> catalog = new ArrayList<>(); List<String> wishlist = new ArrayList<>(); for (int i = 0; i < 1000; i++) catalog.add("SKU-" + i); for (int i = 990; i < 1000; i++) wishlist.add("SKU-" + i); long iterations = 0; // O(n Ɨ m) — 1000 Ɨ 10 = 10,000 iterations for this small case // If catalog were 100,000 items, this becomes 1,000,000 iterations for (String wished : wishlist) { for (String product : catalog) { iterations++; if (product.equals(wished)) { // found — should break here to avoid the rest of the inner loop } } } System.out.println("Total iterations: " + iterations); System.out.println("A HashSet lookup would do this in ~" + wishlist.size() + " iterations."); } }
Output:
Total iterations: 10000
A HashSet lookup would do this in ~10 iterations.

Loading the catalog into a HashSet<String> and using catalogSet.contains(wished) reduces the inner loop entirely — O(n Ɨ m) becomes O(n) with O(m) setup cost. During code reviews, nested loops over large collections are the first place seniors look for avoidable quadratic complexity.

Interview Questions

Q1. What is a nested loop in Java and how does the iteration count work?

A nested loop is a loop placed inside the body of another loop. The inner loop completes all its iterations for every single iteration of the outer loop. The total iteration count is the product of both loop counts — a nested loop where the outer runs M times and the inner runs N times executes M Ɨ N body iterations total. When both M and N scale with the same input size n, the loop is O(n²) — this is the most important characteristic to understand before writing any nested loop.

Q2. How do you exit both loops in a nested loop using break?

A plain break exits only the innermost loop it appears in. To exit an outer loop from inside an inner loop, use a labeled break. You assign a label to the outer loop — outerLabel: — and then break outerLabel; inside the inner loop exits the labeled loop directly. This is the only mechanism in Java for breaking out of more than one loop level simultaneously without using a flag variable or restructuring into a method with return.

Q3. What is the time complexity of a nested loop and when is it acceptable?

A two-level nested loop where both loops scale with the same input size is O(n²). This is acceptable when either the outer or inner iteration count is provably small and bounded — for example, iterating 50 warehouses for each of 200 orders is 10,000 iterations, which is fine. It is not acceptable when both sizes scale with user input — searching through a 100,000-item catalog for each of 50,000 wishlist items produces 5 billion iterations. For large collections, a HashMap or HashSet lookup inside a single loop reduces the complexity to O(n).

Q4. What is a labeled break in Java and when would you use it?

A labeled break exits the loop identified by its label rather than the innermost enclosing loop. You use it when a match found in an inner loop should immediately stop the entire nested search — for example, finding a row and column in a 2D grid, locating a matching record in a nested collection scan, or stopping a multi-level search once the first valid result is found. Without labels, you would need a boolean flag in the outer loop condition to signal early exit, which is more verbose.

Q5. How would you improve a naive O(n²) nested loop search to O(n)?

Load the inner collection into a HashSet before the outer loop begins. Replace the inner loop with a single contains() call on the HashSet, which is O(1) on average. The total complexity becomes O(n) for the outer loop plus O(m) to build the set — O(n + m) instead of O(n Ɨ m). This is the standard optimization that converts pair-searching nested loops into single-pass lookups and is one of the most commonly tested refactoring scenarios in product-based company interviews.

Q6. Can you nest different types of loops in Java?

Yes. Any loop type can be nested inside any other — for inside while, while inside for-each, do-while inside for, and so on. The choice of loop type at each level is independent. Use the loop type that best expresses the iteration intent at that level: for when the count is known, while when termination depends on runtime state, for-each when reading every element without an index.

FAQs

What is a nested loop in Java?

A nested loop is a loop placed inside another loop's body. The inner loop runs completely for every single iteration of the outer loop, producing a total iteration count equal to the product of both loops' iteration counts.

How many levels of nesting are allowed in Java?

Java places no syntactic limit on nesting depth. However, more than two levels is consistently flagged in code reviews as a readability and maintainability problem. Three-level nesting almost always signals that the inner logic should be extracted into a separate method.

What is a labeled break in Java nested loops?

A labeled break exits the loop associated with a specific label — not just the innermost loop. You place the label directly before the outer loop, then write break labelName; inside any inner loop to exit the labeled outer loop immediately.

What time complexity does a nested loop have?

A two-level nested loop is O(n²) when both loop counts scale with the same input size. If the inner loop has a fixed, bounded count, the complexity remains O(n). Always assess the data sizes before writing nested loops over large collections.

How do you break out of both loops at once in Java?

Use a labeled break. Apply a label to the outer loop — outerLoop: — and write break outerLoop; inside the inner loop. This exits both loops immediately without flag variables or restructuring.

Can the inner loop variable depend on the outer loop variable?

Yes. The inner loop's initialization, condition, and update can all reference the outer loop variable. This is exactly how triangular patterns work — the inner loop runs row times on outer iteration row, producing a triangularly shaped output instead of a rectangular one.

Summary

Nested loops express two-dimensional iteration — working through every combination of two sets, processing every cell in a grid, or checking every pair in a collection. The inner loop always resets and runs completely for each outer iteration, and the total execution count is their product.

Two things define whether nested loops are used well in production code. First, the time complexity must be acceptable for the data size — an O(n²) nested loop over bounded, small collections is fine; the same loop over user-scaled data is a performance problem. Second, break exits only the innermost loop, and labeled break is the correct mechanism for exiting outer loops from inside inner ones.

For interviews, be ready to calculate the iteration count of a two-level nested loop, explain why and how you would optimize a nested loop search to O(n) using a HashSet, and demonstrate labeled break with a concrete example. These three points cover the depth that both service-based recall and product-based optimization questions probe on this topic.

What to Read Next

Practice Programs

Put this topic into practice — each program has full code, output and a step-by-step explanation you can run online.

Browse all Java programs →