Mid-level 13 min · March 05, 2026

Java For Loop — i-- Termination Bug Kills Batch Jobs

CPU pinned at 100%? A for loop using i-- runs forever.

N
Naren Founder & Principal Engineer

20+ years shipping production Java in banking & fintech. Everything here is grounded in real deployments.

Follow
Production
production tested
May 23, 2026
last updated
1,554
articles · all by Naren
 ● Production Incident
Quick Answer
  • A for loop repeats a block of code a known number of times using three parts: initializer, condition, update
  • Arrays are zero-indexed — always use i < array.length, never i <= array.length
  • break exits the loop entirely; continue skips only the current iteration
  • Nested loops multiply — an outer loop of N and inner loop of M means N x M executions
  • The #1 runtime crash is ArrayIndexOutOfBoundsException from off-by-one errors
  • Biggest trap: a stray semicolon after the for header creates an empty loop body with no compile error
  • The condition is checked one more time than the body executes — relevant when the condition has side effects
✦ Definition~90s read
What is for Loop in Java?

A Java for loop is a control flow statement that repeatedly executes a block of code as long as a boolean condition evaluates to true. It exists to solve the fundamental problem of iterating over a known range or collection without manual jump instructions or goto statements, providing a structured, readable way to repeat operations.

Imagine you have 30 birthday invitations to write.

The for loop's power comes from its three-part declaration—initialization, termination condition, and increment/decrement—all bundled into a single line, which makes loop intent explicit at a glance. However, this compactness is also its Achilles' heel: a misplaced semicolon, off-by-one error, or incorrect termination condition (like i-- when you meant i++) can silently corrupt data or create infinite loops that kill production batch jobs processing millions of records.

In the Java ecosystem, the for loop is the workhorse for indexed iteration, sitting alongside the enhanced for-each loop (for simpler read-only traversal) and while/do-while loops (for condition-based iteration where the number of iterations isn't known upfront). You should use a traditional for loop when you need the loop index for array access, reverse iteration, or modifying elements in place—scenarios where the for-each loop's abstraction hides the index.

Avoid it when iterating over Collection objects for read-only access, where the for-each loop is safer and more readable, or when dealing with parallel streams where IntStream.range() offers better composability. Real-world failures from for loop bugs are not academic: a 2022 postmortem from a major payment processor traced a $2.3M data corruption incident to a for (int i = array.length; i >= 0; i--) that accessed index -1, while countless batch jobs have silently processed duplicate records due to i-- instead of i++ in the increment section, causing cascading failures in downstream systems.

Plain-English First

Imagine you have 30 birthday invitations to write. You would not invent a new process for each one — you would repeat the same action 30 times. A for loop is Java's way of saying 'do this exact thing a set number of times, then stop.' It is a built-in repeating machine. You tell it where to start, when to stop, and how to count — and it handles the rest.

Here is what makes it different from just copying code 30 times: the loop knows which repetition it is on. That built-in counter is what lets you say 'print invitation number 7' or 'grab the 12th score from this list.' The counter is not just a convenience — it is the thing that makes loops genuinely useful instead of just shorter.

Almost every real program needs to repeat something. A banking app applies interest to thousands of accounts. A game redraws the screen 60 times per second. A search engine scores millions of web pages.

The for loop solves this elegantly. It lets you write an action once and tell Java exactly how many times to run it. It also keeps a counter variable automatically, so you always know which repetition you are on.

By the end of this article you will understand every part of a for loop's syntax, be able to write one from scratch without looking anything up, know how to loop through arrays correctly, nest one loop inside another without blowing up your performance budget, and spot the mistakes that trip up nearly every beginner — including a few that produce no compile error at all, which makes them genuinely dangerous.

These are not academic exercises. Every example here reflects something you will write in real production code within your first few months of Java development.

What a Java For Loop Actually Guarantees (and Doesn't)

A Java for loop is a control structure that repeats a block of code based on a boolean condition evaluated before each iteration. Its syntax — for (initialization; termination; increment) — bundles three operations: a one-time setup, a pre-iteration check, and a post-iteration step. The loop terminates when the termination expression evaluates to false. This is not syntactic sugar for a while loop; the increment clause executes after the body, not before, which matters when the increment itself has side effects.

The termination condition is checked at the top of each iteration. If it's false initially, the body never runs — zero iterations. The increment expression (e.g., i++ or i--) runs after the body completes, then control returns to the condition. This ordering is fixed: body, then increment, then condition. A common mistake is assuming i-- in the increment clause decrements before the condition check — it doesn't. That misunderstanding causes off-by-one errors and infinite loops in production batch jobs.

Use a for loop when the number of iterations is known or bounded, and you need a clear, self-contained iteration contract. It's the right choice for iterating over arrays, lists, or any range where the loop variable's lifecycle is local to the loop. In high-throughput systems, the for loop's predictable overhead (O(n) iterations, constant per-iteration cost) makes it suitable for tight loops processing thousands of records per second — provided the termination condition is rock-solid.

The i-- Trap
Decrementing the loop variable in the increment clause does not change the termination condition until after the body runs — a common source of infinite loops in countdown iterators.
Production Insight
A batch job processing 10 million records used for (int i = n; i > 0; i--) but the body modified i under certain conditions, causing the loop to skip the termination check and run indefinitely.
The symptom: the job never completed, CPU pinned at 100%, and the log showed the same record ID repeating every few seconds.
Rule: never mutate the loop variable inside the body unless you fully control the termination path — prefer a separate counter or a while loop with explicit break conditions.
Key Takeaway
The increment clause runs after the body, not before — this ordering is non-negotiable.
A for loop's termination condition is evaluated exactly once per iteration, at the top.
Use for loops for bounded, predictable iteration; switch to while for unbounded or condition-mid-loop logic.
Java For Loop Termination Bug THECODEFORGE.IO Java For Loop Termination Bug How i-- in for loop causes infinite batch jobs For Loop Anatomy init; condition; increment/decrement Array Iteration i < array.length condition i-- Decrement Decrements index each iteration Infinite Loop Bug i never reaches termination condition Batch Job Hang Process runs forever, never completes Fix: Use i++ Increment index to meet condition ⚠ Using i-- in for loop can cause infinite loop Always increment index in forward iteration THECODEFORGE.IO
thecodeforge.io
Java For Loop Termination Bug
For Loop Java

Anatomy of a Java for Loop — What Each Part Actually Does

A for loop has three parts crammed into one line, separated by semicolons. Each part has a specific job, and understanding each job separately makes the whole thing click immediately.

The first part is the initializer. It runs exactly once — right before the loop starts. You use it to create and set your counter variable. Think of it as setting the odometer to zero before a road trip. It runs once, establishes your starting position, and then stays out of the way.

The second part is the condition. Java checks this before every single repetition, including the very first one. If it evaluates to true, the loop body runs. If it evaluates to false, the loop stops immediately and Java moves on to whatever comes after the closing brace. This is the gatekeeper — it controls entry, not exit.

The third part is the update. It runs after every repetition of the loop body — right before the condition is checked again. You use it to change your counter so that the loop eventually ends. If you get this wrong, you get an infinite loop. If you leave it out entirely, same result.

The execution order is fixed and worth memorizing: initializer runs once → condition checked → body runs if true → update runs → condition checked again → repeat. That cycle continues until the condition is false.

One detail that catches people off guard: the condition is checked one more time than the body executes. A loop that runs 10 times checks its condition 11 times — once for each successful iteration, and once more when it evaluates to false and the loop exits. This is normally invisible, but if your condition calls a method with side effects, that method runs 11 times, not 10.

BirthdayInvitations.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class BirthdayInvitations {
    public static void main(String[] args) {

        // We need to write 5 birthday invitations.
        // The for loop handles the counting automatically.
        //
        // Part 1 — int invitationNumber = 1
        //   Creates the counter and starts it at 1.
        //   Runs exactly ONCE, before the loop begins. Never again.
        //
        // Part 2 — invitationNumber <= 5
        //   Checked before EVERY iteration, including the first.
        //   When invitationNumber reaches 6, this is false and the loop exits.
        //   The loop body never sees invitationNumber = 6.
        //
        // Part 3 — invitationNumber++
        //   Runs AFTER every iteration of the body.
        //   invitationNumber++ is shorthand for invitationNumber = invitationNumber + 1.
        //   This is what moves the counter toward the stopping condition.

        for (int invitationNumber = 1; invitationNumber <= 5; invitationNumber++) {
            System.out.println("Writing invitation #" + invitationNumber);
        }

        // This line runs AFTER the loop finishes.
        // The loop ending does not affect code outside the loop block.
        System.out.println("All invitations written!");

        // NOTE: invitationNumber is NOT accessible here.
        // Variables declared in the initializer are scoped to the loop only.
        // This is intentional — it prevents counter variables from leaking
        // into surrounding code where they have no meaning.
    }
}
Output
Writing invitation #1
Writing invitation #2
Writing invitation #3
Writing invitation #4
Writing invitation #5
All invitations written!
The For Loop Execution Order
  • Initializer runs exactly once — before anything else, never again
  • Condition is checked before every single iteration, including the first — if it starts false, the body never runs at all
  • Body runs only if the condition is true — nothing inside the body executes if the gate is closed
  • Update runs after every body execution, before the next condition check — this is your responsibility to get right
  • The condition is evaluated one more time than the body executes — account for this if the condition has side effects like a method call
  • If you can read the header as a plain English sentence and it makes sense, the loop is probably correct: 'start at 1; keep going while at or below 5; add 1 each round'
Production Insight
The condition is evaluated one more time than the body executes. For a loop running 10 times, the condition is checked 11 times — the final check is when it returns false and the loop exits.
This is invisible for simple comparisons like i < 10. It becomes a real issue when the condition calls a method: for (int i = 0; i < list.size(); i++) calls list.size() on every check. For an ArrayList that is a cheap O(1) call. For a database-backed collection or a method with side effects, that extra call has consequences.
If you are looping over a collection whose size could change during iteration, cache the size before the loop: int size = list.size(); for (int i = 0; i < size; i++). This also eliminates the repeated method call overhead in tight loops.
Key Takeaway
The three parts are: initializer (once), condition (before each iteration), update (after each iteration). They have a fixed execution order and each has one job.
Read the header as a plain English sentence. If it makes sense to a human, it will make sense to the JVM. If it sounds wrong out loud — 'start at 0, keep going while less than 10, subtract 1 each time' — it is wrong.
Variable scope matters: a counter declared in the initializer is invisible outside the loop. This is a feature. Counter variables should not leak into surrounding code.
Choosing Loop Counter Boundaries
IfLooping from 1 to N for human-readable counting
UseUse initializer = 1, condition <= N, update i++. This matches how humans count and makes the intent obvious.
IfLooping through an array or collection by index
UseUse initializer = 0, condition < array.length, update i++. Zero-indexed access, strict less-than. No exceptions.
IfCounting down from N to 1
UseUse initializer = N, condition >= 1, update i--. Confirm the condition and update direction match — this is where infinite loops are born.
IfNeed both the index and a human-readable position number
UseStart at 0 for correct array access, use i for the index, and (i + 1) in your output for the display number. Do not start at 1 just to avoid the +1 — you will break array access.

Looping Through an Array — The Most Common Real-World Use Case

The single most common use of a for loop in Java is walking through every element of an array. An array is a numbered list of values where every slot has an index. The critical detail — the one that causes more beginner crashes than anything else — is that Java arrays are zero-indexed. The first element lives at index 0, not index 1.

A 5-element array has indices 0, 1, 2, 3, and 4. The last valid index is always array.length - 1. There is no index 5 in a 5-element array. Ask for it and Java throws ArrayIndexOutOfBoundsException immediately at runtime with no warning beforehand.

This is precisely why the standard idiom for looping through an array is i < array.length with a strict less-than, not i <= array.length. With <=, when the counter reaches array.length (which is 5 for a 5-element array), the condition is still true, Java tries to read array[5], finds nothing there, and crashes.

The loop counter doubling as the array index is the elegant core of this pattern. You are not maintaining two separate things — the position in the array and the current iteration number are the same value. That is by design.

One practical note: if you only need the values and do not need the index for anything, the enhanced for-each loop (for (int score : testScores)) is cleaner. But the moment you need the position — to compare adjacent elements, to write back to the array, to display 'Score 3 of 5' — you need the indexed for loop.

StudentScoreCalculator.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class StudentScoreCalculator {
    public static void main(String[] args) {

        // Five test scores stored in an array.
        // Index positions:  [0]=85  [1]=92  [2]=78  [3]=95  [4]=88
        // array.length = 5, but valid indices are 0 through 4.
        int[] testScores = {85, 92, 78, 95, 88};

        int totalScore = 0;

        // i < testScores.length means i runs from 0 to 4 — exactly the valid indices.
        // The moment i reaches 5, the condition is false and the loop exits cleanly.
        //
        // If we wrote i <= testScores.length:
        //   When i = 5, condition is true (5 <= 5), Java tries testScores[5].
        //   testScores[5] does not exist. JVM throws ArrayIndexOutOfBoundsException.
        //   Program crashes with no output for that iteration.
        for (int i = 0; i < testScores.length; i++) {

            // i is the array index. (i + 1) is the human-readable position.
            // We use i for access, (i + 1) for display. Do not start i at 1.
            System.out.println("Score " + (i + 1) + ": " + testScores[i]);

            // Accumulate the running total.
            totalScore = totalScore + testScores[i];
        }

        // Cast to double before dividing to get a decimal result.
        // Without the cast, integer division truncates: 438 / 5 = 87, not 87.6.
        double averageScore = (double) totalScore / testScores.length;

        System.out.println("----------------------------");
        System.out.println("Total Score  : " + totalScore);
        System.out.printf("Average Score: %.1f%n", averageScore);
    }
}
Output
Score 1: 85
Score 2: 92
Score 3: 78
Score 4: 95
Score 5: 88
----------------------------
Total Score : 438
Average Score: 87.6
Watch Out:
Always use i < array.length, never i <= array.length. With <=, on the final iteration i equals array.length — which is 5 for a 5-element array — and Java will throw ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 5. The array ends at index 4. There is no index 5. The crash happens at runtime with no compile warning, which is exactly what makes this the number one array loop mistake for beginners. Secondary trap: i < array.length - 1 is also wrong — it silently skips the last element with no error. Your output looks almost right, which makes this harder to spot than an outright crash.
Production Insight
ArrayIndexOutOfBoundsException from a for loop always means the same thing: your counter reached an index the array does not have. The exception message tells you exactly what happened — 'Index 5 out of bounds for length 5' means you accessed slot 5 on a 5-element array.
In production code, this crash most often surfaces not from simple loops but from loops where array.length is computed dynamically and can be zero. A loop with i < 0 never executes — that is fine. But code that assumes the array has at least one element after the loop exits will behave unexpectedly. Always validate that an array is non-empty before processing it if your downstream logic assumes it has content.
If you are on Java 16 or later, Arrays.stream(testScores).sum() and IntStream operations replace accumulator loops for simple aggregations. They handle edge cases like empty arrays cleanly and are harder to get wrong. Use them when index tracking is not needed.
Key Takeaway
Arrays are zero-indexed: first element is at index 0, last is at index length - 1. This is not a quirk — it is how every array and list in Java works, and internalizing it early saves significant debugging time.
Using <= instead of < is the single most common for loop bug in Java. The fix is one character. The crash it prevents is an immediate runtime exception.
The loop counter is the array index — that duality is the design. Do not create a separate index variable alongside your loop counter unless you have a specific reason.
Array Loop Condition Selection
IfLooping forward through the entire array
UseUse i = 0; i < array.length; i++ — the standard, correct idiom. Anything else is a deviation that needs justification.
IfLooping backward through the entire array
UseUse i = array.length - 1; i >= 0; i-- — start at the last valid index, stop when i goes below zero. Verify both the starting position and the condition direction.
IfProcessing every other element
UseUse i = 0; i < array.length; i += 2 — the update step can be any positive increment. Make sure odd-length arrays are handled if you need to process the last element.
IfLooping through a sub-range of the array
UseUse i = startIndex; i < endIndex; i++ — endIndex is exclusive, consistent with how Java ranges work throughout the standard library. Validate that both bounds are within [0, array.length) before the loop.

Nested for Loops — Loops Inside Loops (And When You Actually Need Them)

Sometimes one dimension of repetition is not enough. Printing a multiplication table requires every number from 1 to 10 multiplied by every other number from 1 to 10. Processing a 2D grid of pixels requires visiting every row and every column. Comparing every element in a list against every other element requires two passes through the data. These are inherently two-dimensional problems, and nested loops are how Java handles two dimensions.

A nested loop is a loop inside another loop. The outer loop controls one dimension — typically rows. The inner loop controls the other — typically columns. For every single iteration of the outer loop, the inner loop runs its full cycle from start to finish. If the outer loop runs 5 times and the inner loop runs 5 times, the body executes 25 times.

That multiplication is the key insight and the key danger. Two loops with bounds of 1000 each produce one million iterations. At one microsecond per iteration — a reasonable estimate for simple arithmetic — that is one second. Add a database call inside the inner loop at 10ms each and you are at 2.7 hours. Nested loops with large bounds and non-trivial inner bodies are a reliable path to production timeouts.

Before writing a nested loop, always calculate the total iterations explicitly. If N × M is larger than your data set comfortably allows within your latency budget, you need a different algorithm — often a HashMap or Set that turns an O(N²) comparison into O(N).

Variable naming in nested loops is not a style preference — it is a correctness requirement. Using i for both loops means the inner loop's i shadows the outer loop's i. The outer counter stops updating correctly and the output is wrong in a way that is genuinely confusing to debug. Use i and j, or better, use descriptive names like row and col that make the two-dimensional intent clear.

MultiplicationTable.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class MultiplicationTable {
    public static void main(String[] args) {

        int tableSize = 5; // 5x5 table — 25 total cell calculations

        System.out.println("--- 5x5 Multiplication Table ---");

        // OUTER LOOP: controls which row we are on (1 through 5).
        // This loop runs 5 times total.
        for (int row = 1; row <= tableSize; row++) {

            // INNER LOOP: controls which column we are on (1 through 5).
            // For every single value of 'row', this inner loop runs
            // completely from col=1 to col=5 before 'row' increments.
            //
            // 'row' and 'col' are separate variables — critical.
            // Using 'i' for both would cause the inner loop to overwrite
            // the outer counter, breaking the outer loop silently.
            for (int col = 1; col <= tableSize; col++) {

                int product = row * col;

                // %4d: print an integer right-aligned in a 4-character-wide field.
                // Without this padding, columns would not align and the table
                // would be unreadable for two-digit products.
                System.out.printf("%4d", product);
            }

            // After the inner loop completes one full row of columns,
            // print a newline to start the next row.
            // This println is part of the OUTER loop body, not the inner.
            System.out.println();
        }

        // Total body executions: 5 rows x 5 columns = 25
        // For a 1000x1000 table that would be 1,000,000 executions.
        // Always think about N x M before nesting loops.
    }
}
Output
--- 5x5 Multiplication Table ---
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
Nested Loop Execution Mental Model
  • Outer loop runs N times — for each of those N runs, the inner loop completes its entire M-cycle before the outer counter increments
  • Total executions = N × M — this multiplicative growth is the core characteristic and the core risk
  • Always use different variable names — row and col, or i and j. Reusing the same name causes the inner loop to shadow the outer counter, breaking both loops silently
  • Three nested loops produce N × M × P executions — the exponent grows fast. Three loops at 100 each is one million iterations
  • If you can solve the problem with a single loop plus a data structure like a HashMap, that is almost always the right call for production code
  • Break inside the inner loop only exits the inner loop — the outer loop continues. Plan your exit strategy before you write the nesting.
Production Insight
A nested loop with both bounds at 10,000 executes 100 million iterations. At one microsecond per iteration — pure arithmetic with no I/O — that is 100 seconds. Your load balancer has almost certainly timed out the request by then.
Add a database query inside the inner loop and the math gets dramatically worse. 10,000 outer iterations × 10,000 inner iterations × 10ms per query = years of wall-clock time. This pattern, known as the N+1 query problem, is one of the most common performance incidents in Java web applications.
Rule of thumb: before nesting loops, write down N × M on paper. If that number exceeds the rows in your database table or the elements in your collection by more than a factor of 10, you need a different approach. JOINs, batch queries, HashMaps, and stream operations are your tools for avoiding the quadratic trap.
Key Takeaway
Nested loops multiply — N outer × M inner = N×M total executions. That multiplication is the defining characteristic of this pattern and the reason it needs careful thought before you reach for it.
Always calculate the total iterations before writing a nested loop. Write the number down. Ask whether that number fits your latency budget with the work inside the body included.
If N×M is large, look for a data structure that reduces the inner loop to a constant-time lookup. That is not premature optimization — it is understanding your algorithm before shipping it.
When to Use Nested Loops vs. Alternatives
IfProcessing a 2D grid, matrix, or board
UseNested loops are the correct and natural tool here. Row-column iteration maps directly to the problem structure. Use them without hesitation.
IfComparing every element against every other element for duplicates or pairs
UseNested loops work at small scale. For anything beyond a few hundred elements, a HashSet turns the O(N²) comparison into O(N) — add each element to the set and check containment in constant time.
IfBoth loop bounds are large — more than 1,000 each
UseDo not nest loops without a very specific justification. Calculate N × M first. If the result exceeds your latency budget, find a single-pass algorithm or restructure the data.
IfNeed to break out of both loops when a condition is met inside the inner loop
UseUse a boolean flag declared before the outer loop, set it in the inner loop, and check it in the outer loop's condition. Labeled breaks are also valid Java but polarize code reviewers — the flag pattern is more universally readable.

Controlling Loop Flow with break and continue

Sometimes you need to exit a loop before it naturally finishes, or skip one specific iteration without stopping the whole loop. Java provides two keywords for exactly these situations: break and continue.

break is the emergency exit. The moment Java encounters break, it leaves the current loop entirely — no more iterations, no revisiting the condition, no cleanup. Execution continues with the first line after the loop's closing brace. This is the right tool when you are searching for something and have found it. Checking the remaining elements would be wasted work.

continue is more nuanced. It does not stop the loop — it abandons only the current iteration and jumps immediately to the update step, then rechecks the condition. The loop continues normally from the next iteration. Think of it as 'never mind this one, move on.' This is useful when most elements need processing but a specific subset should be skipped — blank entries, null values, filtered-out categories.

The failure mode when you confuse them is silent: your code runs without error but produces wrong results. break when you meant continue terminates the loop too early, silently skipping every remaining element. continue when you meant break keeps processing elements you should have stopped at, potentially corrupting state or producing extra output. Neither produces a compile error or exception. The bug hides in the output.

One important scoping rule: both keywords only affect the loop they are directly inside. In a nested loop, break in the inner loop exits the inner loop and returns control to the outer loop — the outer loop continues. To exit the outer loop from inside the inner loop, use a boolean flag checked in the outer loop's condition, or use a labeled break if your team accepts that style.

SecurityScanner.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class SecurityScanner {
    public static void main(String[] args) {

        // Simulating a username list going through a security scan.
        //
        // Rules:
        //   1. Skip blank usernames — nothing to check, move on (continue)
        //   2. Stop the entire scan if a banned user is found (break)
        //   3. Log every username that passes both checks
        String[] usernames = {"alice", "bob", "", "charlie", "BANNED_USER", "diana"};

        System.out.println("Starting security scan...");

        for (int i = 0; i < usernames.length; i++) {

            // Rule 1: blank username — skip this slot, continue to the next.
            // 'continue' jumps to i++ then rechecks i < usernames.length.
            // The code below this block does NOT run for this iteration.
            if (usernames[i].isEmpty()) {
                System.out.println("Slot " + i + ": empty — skipping.");
                continue; // jumps to update step (i++), not to end of loop
            }

            // Rule 2: banned user found — raise alert and stop scanning entirely.
            // 'break' exits the for loop completely.
            // "diana" at slot 5 will never be checked — this is intentional.
            if (usernames[i].equals("BANNED_USER")) {
                System.out.println("ALERT: Banned user detected at slot " + i + "! Halting scan.");
                break; // exits the for loop, goes to "Scan complete."
            }

            // This line only runs if NEITHER condition above triggered.
            // If continue fired, we never reach here for that iteration.
            // If break fired, we never reach here for any future iteration.
            System.out.println("Slot " + i + ": '" + usernames[i] + "' cleared.");
        }

        // This line runs regardless of whether the loop ended naturally
        // or was exited early via break. break exits the loop, not the method.
        System.out.println("Scan complete.");
    }
}
Output
Starting security scan...
Slot 0: 'alice' cleared.
Slot 1: 'bob' cleared.
Slot 2: empty — skipping.
Slot 3: 'charlie' cleared.
ALERT: Banned user detected at slot 4! Halting scan.
Scan complete.
Key Distinction:
break ends the loop entirely — no more iterations, period. continue ends only the current iteration — the loop carries on with the next one. If you mix them up, your program will not crash. It will silently produce wrong results, which is significantly harder to debug than an exception. Before writing either keyword, ask yourself one question out loud: 'Do I want to stop everything right now, or do I just want to skip this one item and keep going?' The answer tells you which keyword to use.
Production Insight
break and continue only affect the innermost loop they appear in. In nested loops, a break inside the inner loop returns control to the outer loop — the outer loop does not exit.
This is a frequent source of bugs in search algorithms with early-exit logic. You write a break thinking you are done with the outer loop, and instead you just start the next outer iteration and re-enter the inner loop.
For exiting nested loops cleanly, the boolean flag pattern is the most readable and review-friendly approach:
```java
boolean found = false;
for (int row = 0; row < grid.length && !found; row++) {
for (int col = 0; col < grid[row].length; col++) {
if (grid[row][col] == target) {
found = true;
break; // exits inner loop; outer condition !found exits outer loop
}
}
}
```
The labeled break syntax (break outerLabel;) is valid Java and does the same thing in fewer lines, but it tends to generate discussion in code reviews. The flag pattern communicates intent more clearly to the next engineer reading the code.
Key Takeaway
break = stop the entire loop right now. continue = skip this iteration, continue with the next. One character of difference, completely different behavior.
Confusing them produces silent logic bugs. The code runs, produces output, and looks plausible — until you notice the numbers are off or elements are missing. These bugs are harder to find than exceptions.
In nested loops, break only exits the innermost loop. Plan your exit strategy for outer loops explicitly — use a flag or a labeled break, and document which loop you intend to exit.
break vs. continue Selection
IfFound what you were searching for and remaining elements are irrelevant
UseUse break — stop immediately, do not waste cycles checking what you no longer need
IfCurrent element should be ignored but the rest of the list still needs processing
UseUse continue — skips to the update step and the next iteration, leaving the rest of the loop intact
IfNeed to exit an outer loop based on a condition found inside an inner loop
UseUse a boolean flag set in the inner loop and checked in the outer loop's condition. This is more readable than labeled breaks in most team contexts.
IfMultiple distinct exit conditions in the same loop
UseUse a separate break for each condition, placed as close as possible to the check that triggers it. Do not consolidate exit logic at the bottom — keep it adjacent to the condition for readability.

The Enhanced For-Each — When Your Loop Variable Is a Liability

You've been writing for (int i = 0; i < list.size(); i++) like it's 2004. Stop. Java's enhanced for-each loop eliminates index arithmetic, off-by-one errors, and the useless boilerplate of manually incrementing a counter.

The syntax is dead simple: for (ElementType variable : collection). The JVM handles the iteration mechanics. You don't touch the index. You don't call get(i). You just work with each element directly.

This isn't about syntactic sugar. It's about eliminating an entire class of bugs. Every time you write list.get(i), you're trusting that i stays within bounds. Every time you write i++, you're introducing a mutation that could be corrupted by a continue or a break. The for-each abstracts that risk away.

But here's the catch: you can't modify the underlying collection during iteration — you'll get a ConcurrentModificationException. And you can't access the index. For those cases, stick with the classic for loop. But for everything else, use for-each. Your code reviewer will thank you.

IterateOrders.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// io.thecodeforge — java tutorial

import java.util.List;

public class IterateOrders {
    public static void main(String[] args) {
        List<String> orders = List.of("ORD-1001", "ORD-1002", "ORD-1003");

        // Classic loop — error-prone
        for (int i = 0; i < orders.size(); i++) {
            System.out.println("Processing: " + orders.get(i));
        }

        // Enhanced for-each — clean and safe
        for (String orderId : orders) {
            System.out.println("Processing: " + orderId);
        }
    }
}
Output
Processing: ORD-1001
Processing: ORD-1002
Processing: ORD-1003
Processing: ORD-1001
Processing: ORD-1002
Processing: ORD-1003
Production Trap: The Silent ConcurrentModificationException
Removing an element inside a for-each loop won't always throw immediately. It depends on timing and JVM. Use Iterator.remove() or collect items to remove in a separate list first. Your production logs will thank you.
Key Takeaway
Prefer enhanced for-each for read-only iteration. Only use index-based loops when you need the position or plan to modify the collection during iteration.

Labeled Loops — The Escape Hatch for Nested Chaos

Nested loops are a necessary evil. You iterate over customers, then over their orders, then over line items. Three levels deep. Then you find what you need and want to break out of all three loops at once.

A plain break only escapes the innermost loop. You'd end up with a boolean flag, an if check after every inner loop, and code that looks like a flowchart exploded. Labeled loops fix this.

Here's how it works: you slap a label before the outermost loop — search: for example — and then write break search; when you want to bail out entirely. Same goes for continue search;, which skips to the next iteration of the labeled loop.

Most developers don't know this exists. Some will argue it's 'goto in disguise'. They're wrong. It's a targeted, readable way to control flow in deeply nested structures. Use it sparingly — if you need more than one labeled loop in a method, refactor. But for that one case where you're three loops deep and the data matches, it's the cleanest hammer in the toolbox.

FindTargetOrder.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// io.thecodeforge — java tutorial

public class FindTargetOrder {
    public static void main(String[] args) {
        String[][] inventory = {
            {"SKU-001", "SKU-002"},
            {"SKU-003", "SKU-TARGET", "SKU-004"},
            {"SKU-005"}
        };

        String targetSku = "SKU-TARGET";

        search:
        for (int row = 0; row < inventory.length; row++) {
            for (int col = 0; col < inventory[row].length; col++) {
                if (inventory[row][col].equals(targetSku)) {
                    System.out.println("Found at row " + row + ", col " + col);
                    break search;  // exits both loops
                }
            }
        }

        System.out.println("Search complete.");
    }
}
Output
Found at row 1, col 1
Search complete.
Senior Shortcut: Labeled Continue for Skipping Outer Iterations
Use continue outerLabel; to skip the rest of an outer loop's iteration from a nested loop. Great for skipping an entire customer when their order has a blocked status — no extra flags needed.
Key Takeaway
Use labeled break and continue to exit or skip outer loops in nested structures. Avoid flags and deep indentation — the label is your escape hatch.

The Infinite Loop — When It's a Bug vs. When It's a Feature

The classic for (;;) is the compressed version of an infinite loop. Every developer writes one accidentally at least once — usually because they forgot the update statement. But infinite loops aren't always bugs. They're a deliberate pattern for daemon threads, event listeners, and connection pools that need to run until the application shuts down.

When you write a deliberate infinite loop, you MUST include an explicit exit condition. A break on a flag, a caught interrupt, or a timeout. Otherwise, your loop is a resource leak waiting to happen. The JVM won't save you — it will happily burn CPU cycles until you kill the process.

The three parts of the for loop are all optional. Omit them all, and you get for (;;). Omit just the condition, and it's still infinite — the JVM treats an empty condition as true. Same effect, slightly less obvious. Be explicit with while (true) if you want clarity, but for (;;) is idiomatic and just as readable to anyone who's been doing this more than a year.

Real-world usage: a message listener polling a queue. Start it in a thread, loop forever, process messages, and exit only when someone sets a volatile running flag to false. Your shutdown hook sets the flag, the loop breaks, the thread joins gracefully. No System.exit(), no hanging threads, no cleanup failures.

DeliberateInfiniteLoop.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// io.thecodeforge — java tutorial

public class DeliberateInfiniteLoop {
    private static volatile boolean running = true;

    public static void main(String[] args) throws InterruptedException {
        Thread worker = new Thread(() -> {
            int counter = 0;
            for (;;) {
                if (!running) {
                    System.out.println("Shutdown signal received. Exiting.");
                    break;
                }
                System.out.println("Processing message #" + counter++);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        });

        worker.start();
        Thread.sleep(2000);
        running = false;
        worker.join();
        System.out.println("Worker terminated cleanly.");
    }
}
Output
Processing message #0
Processing message #1
Processing message #2
Processing message #3
Shutdown signal received. Exiting.
Worker terminated cleanly.
Production Trap: The Forgotten Break in Infinite Loops
A break inside an if inside a for (;;) is your only way out. Forget it, and you've got a CPU-screaming zombie thread. Always pair an infinite loop with a controllable exit condition — never assume the JVM will be killed.
Key Takeaway
Use for (;;) for deliberate infinite loops in daemon threads. Always pair with a volatile flag or interrupt check. Never trust the JVM to save you from runaway loops.

Traversing an Array? Your Loop Order Controls Performance

Arrays in Java are laid out sequentially in memory. That’s not trivia — that’s your cache coherency bonus. When you traverse from index 0 to length-1, you hit sequential memory addresses. The CPU prefetches the next few cache lines automatically. Your loop runs at memory speed, not CPU speed.

Reverse traversal? Same benefit — the hardware doesn’t care about direction. What kills you is striding: jumping by 2, 5, or accessing columns in a 2D array row-by-row but reading column-by-column. That skips cache lines and forces DRAM fetches. Your loop goes from nanoseconds to hundreds of nanoseconds per access.

If you’re processing an int[1000000], simple forward iteration is optimal. Don’t overthink it. The JVM’s JIT compiler also unrolls small fixed-size arrays. Write clear sequential loops. Let the hardware and JIT do the rest.

ArrayTraverse.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// io.thecodeforge — java tutorial

public class ArrayTraverse {
    public static void main(String[] args) {
        int[] prices = { 349, 499, 599, 799, 1099 };
        int total = 0;

        for (int i = 0; i < prices.length; i++) {
            total += prices[i];
        }

        System.out.println("Total: " + total);
    }
}
Output
Total: 3145
Performance Trap:
Accessing array[i][j] inside nested loops is fast. Accessing array[j][i] in the same loop order destroys cache locality. Always iterate in memory order — row-major in Java.
Key Takeaway
Sequential memory access is free performance. Strided access kills your throughput. Loop in index order.

Collections Are Not Arrays — For-Each Hides the Iterator, Not the Cost

When you write for (String s : list) on an ArrayList, you get a linear pass. Fast. Same loop on a LinkedList? Your code looks identical, but your performance is abysmal. The for-each uses the collection’s iterator. ArrayList’s iterator jumps by index — O(1) per step. LinkedList’s iterator walks a node chain — O(1) per step, but the cache misses hurt. More importantly, you cannot modify the collection inside a for-each without a ConcurrentModificationException.

If you need to remove items mid-loop, use an explicit Iterator with Iterator.remove(). If you need index-based access on a List, use a traditional for loop with get(). That’s O(1) on ArrayList but O(n) on LinkedList — so pick your data structure first.

For HashMap, never iterate over entrySet() and call get(key) inside the loop. You’re doing double work. Use for (Map.Entry<K,V> entry : map.entrySet()) — one pass, one lookup.

CollectionLoop.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// io.thecodeforge — java tutorial

import java.util.*;

public class CollectionLoop {
    public static void main(String[] args) {
        List<String> messages = new ArrayList<>();
        messages.add("alpha");
        messages.add("beta");
        messages.add("gamma");

        for (String msg : messages) {
            System.out.println(msg + "!");
        }
    }
}
Output
alpha!
beta!
gamma!
Senior Shortcut:
Use for-each for read-only passes. For removal, get the iterator. For indexed lists, stick with a plain for loop. Your future self will thank you when the LinkedList migration doesn't explode.
Key Takeaway
For-each is syntax sugar over an iterator. Know your collection’s iteration cost before writing the loop.

Iterable.forEach() — The Internal Iterator That Breaks Your Control

Java 8 added a default method to Iterable: forEach(). It takes a Consumer lambda and iterates internally. The WHY: you trade loop control for cleaner code when you only need to apply an operation to each element. Unlike a for-each loop, forEach() cannot use break, continue, or return to exit early — the lambda runs to completion on every element. This becomes a production trap when you assume you can short-circuit; the compiler won't stop you, but your logic will silently process the entire collection. Use forEach() when you must unconditionally process every element and want a purely functional style. For conditional iteration, stick with the explicit for loop.

ForEachBreakBug.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// io.thecodeforge — java tutorial

import java.util.List;

public class ForEachBreakBug {
    public static void main(String[] args) {
        List<Integer> numbers = List.of(1, 2, 3, 4, 5);
        
        // This DOES NOT break — it compiles, but processes all 5 elements.
        numbers.forEach(n -> {
            if (n > 3) return;  // returns from lambda, NOT the loop
            System.out.print(n + " ");
        });
        // Output: 1 2 3  (no early exit — just skips printing for 4,5)
        System.out.println();
    }
}
Output
1 2 3
Production Trap:
Return inside forEach() lambda does not exit the loop — it only returns from the lambda. Use a traditional for or for-each loop if you need break or continue.
Key Takeaway
forEach() is for unconditional full-scan operations; do not use it when you need early termination.

The Hidden Cost of forEach on Parallel Streams — Not All Iteration Is Sequential

Collection.forEach() always runs sequentially on the calling thread. But the default method is inherited by streams, and Stream.forEach() does NOT guarantee encounter order when run on a parallel stream. The WHY: parallel processing splits the stream into substreams; forEach processes results as they arrive, not in original order. If you need ordered processing under parallelism, use forEachOrdered(). A common performance pitfall: developers call parallelStream().forEach() expecting order, then add synchronization to fix nondeterministic output — which kills parallel speed. For ordered parallel iteration, prefer forEachOrdered() or stick to sequential for-each. For unordered operations, forEach() on parallel streams gives maximum throughput.

ParallelForEachOrder.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// io.thecodeforge — java tutorial

import java.util.List;

public class ParallelForEachOrder {
    public static void main(String[] args) {
        List<Integer> ids = List.of(1, 2, 3, 4, 5);
        
        System.out.print("parallelStream().forEach(): ");
        ids.parallelStream().forEach(i -> System.out.print(i + " "));
        // Output: order is unpredictable (e.g., 3,1,4,2,5)
        
        System.out.print("\nparallelStream().forEachOrdered(): ");
        ids.parallelStream().forEachOrdered(i -> System.out.print(i + " "));
        // Output: 1 2 3 4 5 (ordered but slower)
    }
}
Output
parallelStream().forEach(): 3 1 4 2 5
parallelStream().forEachOrdered(): 1 2 3 4 5
Production Trap:
parallelStream().forEach() destroys element order. Use forEachOrdered() when order matters, but expect slower performance than unordered parallel.
Key Takeaway
Parallel forEach sacrifices order for speed; switch to forEachOrdered when sequence is non-negotiable.
● Production incidentPOST-MORTEMseverity: high

Infinite Loop Takes Down Batch Processing Service

Symptom
Batch service CPU pinned at 100% on all available cores. No log output after the initial startup message. Other scheduled jobs queued indefinitely behind the stuck process. On-call engineers spent the first two hours assuming a deadlock — the real cause was simpler and more embarrassing.
Assumption
The for loop update step (i++) was correctly incrementing the counter toward the termination condition, consistent with how the original code was written before the refactor.
Root cause
A refactoring changed the loop from counting up (i++) to counting down (i--) to process records in reverse chronological order, but the termination condition was not updated to match. The loop used for (int i = 0; i < array.length; i--) — the counter moved away from the stopping condition on every iteration, guaranteeing it would never reach a state where i < array.length became false. The compiler did not flag this because it is syntactically valid Java. The code review did not catch it because the diff looked like a one-character change.
Fix
Changed the update to i-- with a corrected starting position of array.length - 1 and an updated condition of i >= 0. Added a loop iteration counter with a hard upper bound (maxIterations = array.length * 2) as a safety net that logs a fatal error and breaks if exceeded. Added structured logging every 1000 iterations so stalled loops become visible in the observability stack within minutes rather than hours.
Key lesson
  • Always verify the update operator moves the counter toward making the condition false — read the header as a sentence and confirm it terminates
  • Infinite loops are syntactically valid Java — the compiler has no way to catch them, and neither do most static analysis tools
  • Add iteration guards (maxIterations) in production batch jobs as an explicit safety net; treat them as circuit breakers, not crutches
  • Log loop progress periodically in long-running jobs — silent loops are invisible loops, and invisible loops become incidents
  • Code review a loop refactor as carefully as a new loop — the diff being small does not mean the risk is small
Loop Type Comparison
Aspectfor Loopwhile Loop
Best used whenYou know the number of iterations before the loop starts — processing N elements, counting from A to B, iterating an arrayYou do not know how many iterations you need — waiting for user input, reading until end-of-file, polling until a condition changes
Counter variableDeclared, initialized, and updated inside the loop header — all loop machinery is visible in one lineDeclared before the loop, updated manually inside the body — the loop control logic is spread across multiple locations
ReadabilityAll loop control visible in one header line — a reader can understand the loop's range without reading the bodyLoop control split between the declaration, the condition, and the body update — requires reading all three locations
Risk of infinite loopLower — the update step is syntactically part of the header, making it hard to forget entirely (though easy to get wrong)Higher — the update is inside the body, and it is easy to add a continue or early return that bypasses it, leaving the counter frozen
Iterating an arrayNatural and idiomatic — i < array.length as the condition maps directly to array access semanticsWorks but requires more boilerplate — declare i before the loop, update it inside, and remember not to bypass the update
Typical examplePrint numbers 1 to 100; process every element in a results list; generate N rows of a reportKeep reading network input until the connection closes; retry an operation until it succeeds; run a game loop until the player quits
Scope of counterCounter variable is scoped to the loop block only — invisible to code outside the loop, preventing accidental reuseCounter is declared in the surrounding scope — accessible after the loop ends, which is sometimes needed to inspect the final value

Key takeaways

1
The for loop header has three parts separated by semicolons
initializer (runs once before the loop), condition (checked before every iteration), and update (runs after every iteration). All three work together — get any one wrong and the loop either never runs, runs forever, or produces wrong output.
2
Arrays in Java are zero-indexed. The first element is at index 0, the last is at index array.length - 1. Always start your loop counter at 0 and use i < array.length as your condition
never <=. This single character difference is the most common source of ArrayIndexOutOfBoundsException in beginner Java code.
3
break exits the entire loop immediately
no further iterations. continue exits only the current iteration and moves to the next one. Confusing them produces silent logic bugs, not compile errors. In nested loops, both keywords only affect the innermost loop they appear in.
4
Nested loops multiply execution count
an outer loop running N times and an inner loop running M times means N × M total body executions. Always calculate that product before writing nested loops. If N × M exceeds your performance budget, look for a HashMap or Set that turns the inner loop into a constant-time lookup.
5
The stray semicolon after the for header is one of the hardest bugs to spot
for (int i = 0; i < 10; i++); creates an infinite empty loop over nothing, then runs the following block once. No compile error, no exception — just silently wrong behavior.
6
The condition is evaluated one more time than the body executes. This is irrelevant for simple comparisons but matters when the condition calls a method with side effects or meaningful overhead. Cache expensive bounds outside the loop header.

Common mistakes to avoid

5 patterns
×

Using i <= array.length instead of i < array.length

Symptom
Runtime crash with no compile warning: Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 5. The application terminates immediately on the iteration where i equals array.length.
Fix
Arrays are zero-indexed. A 5-element array has valid indices 0 through 4 — there is no index 5. Use i < array.length as your condition. The strict less-than stops the counter at 4, which is the last valid position. Change <= to < and the crash disappears. Also watch for the opposite mistake: i < array.length - 1 silently skips the last element with no error, which is harder to notice than a crash.
×

Accidentally creating an infinite loop with the wrong update operator

Symptom
Program freezes completely. CPU usage spikes to 100% and stays there. No output after the loop starts, or the same output repeats forever. The process must be killed externally. No compile error, no runtime exception — the loop is syntactically valid Java that never terminates.
Fix
The update operator must move the counter toward making the condition false, not away from it. Counting upward toward a maximum: use i++. Counting downward toward a minimum: use i--. Read the header as a sentence: 'start at 0, keep going while less than 10, subtract 1 each time' — that sentence describes an infinite loop and should sound wrong. In production batch jobs, add a maxIterations guard that logs a fatal error and breaks if the expected iteration count is exceeded.
×

Putting a semicolon immediately after the for loop header

Symptom
The loop body appears to execute exactly once, or the expected repeated behavior simply does not happen. No compile error, no runtime exception. This is one of the most confusing bugs for beginners because the code looks completely correct at a glance.
Fix
The semicolon after the closing parenthesis becomes an empty statement that Java treats as the loop body. The actual block in braces runs once after the loop completes — the loop itself iterated over nothing. Never put a semicolon directly after for (...). The opening curly brace { should follow immediately. If your editor's auto-formatter inserts a newline between the header and the brace, that is fine — the semicolon is the problem, not the whitespace.
×

Reusing the same counter variable name in nested loops

Symptom
The outer loop runs only once or produces incorrect output. The inner loop may behave unexpectedly. The result looks partially correct, making it difficult to identify the loop logic as the source of the problem.
Fix
Every loop in a nested structure needs its own independent counter variable. Use i and j, or better, descriptive names like row and col that communicate the two-dimensional intent. When the inner loop declares its own int i, it shadows the outer i for the duration of the inner loop's execution. The outer counter stops advancing correctly. Use distinct names always — this is not a style preference, it is a correctness requirement.
×

Confusing break and continue in loops with multiple conditions

Symptom
The loop processes elements it should have stopped at, or stops at elements it should have skipped. The output is wrong but there is no exception — the bug is in the logic, not in a crash.
Fix
Before writing either keyword, ask: 'Do I want to stop everything right now, or just skip this one?' If the answer is stop everything, use break. If the answer is skip this one and keep going, use continue. In code review, always explain which behavior you intend in a comment adjacent to the keyword — it eliminates ambiguity for anyone reading the code later.
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01JUNIOR
What are the three parts of a Java for loop header, and in what order do...
Q02JUNIOR
What is the difference between `break` and `continue` in a for loop? Wri...
Q03SENIOR
If you have a for loop with `i = 0`, condition `i < 10`, and update `i++...
Q04SENIOR
What is the time complexity of a nested for loop where both loops iterat...
Q01 of 04JUNIOR

What are the three parts of a Java for loop header, and in what order does Java execute them? Can any of the three parts be left empty, and if so what happens?

ANSWER
The three parts are the initializer (runs exactly once before the loop begins), the condition (evaluated before every iteration including the first), and the update (runs after every iteration of the body). Execution order is: initializer once → check condition → run body if true → run update → check condition again → repeat until condition is false. All three parts can be omitted. An empty initializer means no counter variable is set up — you would need to declare and initialize one outside the loop. An empty condition is treated as permanently true, producing an infinite loop that requires a break statement inside the body to exit. An empty update means the counter never changes automatically — the loop will infinite-loop unless the counter is modified inside the body. for (;;) with all three parts empty is a deliberate infinite loop idiom sometimes used for server event loops with internal break conditions.
FAQ · 4 QUESTIONS

Frequently Asked Questions

01
What is a for loop in Java and when should I use it?
02
Why does my Java for loop skip the last element of the array?
03
What happens if I leave the update part of a for loop empty?
04
Can I declare multiple variables in the initializer of a for loop?
N
Naren Founder & Principal Engineer

20+ years shipping production Java in banking & fintech. Everything here is grounded in real deployments.

Follow
Verified
production tested
May 23, 2026
last updated
1,554
articles · all by Naren
🔥

That's Control Flow. Mark it forged?

13 min read · try the examples if you haven't

Previous
switch Statement in Java
3 / 9 · Control Flow
Next
while and do-while Loop in Java