The for Loop and the Definite Loop
Three parts on one line, and the one problem they solve exactly right
A while loop keeps the counter management scattered. You declare the counter above the loop, you increment it inside the body, and the condition sits in the middle. The for loop collects all three pieces into the header so a reader can understand the loop’s shape in a single glance.
This lesson is about two things: the mechanics of the for header (which is trickier than it looks because it runs in a specific order), and the definite loop — the one problem for loops solve exactly right, namely “do something exactly n times.”
In a nutshell
A for header has three parts: init, condition, update. The init runs once before the first condition check. The condition is checked before every iteration, including the first. The update runs after each body execution, before the next condition check. Get the order wrong in your head and the bugs are subtle.
Loop-variable scope is the header. A counter declared in the for header exists only inside the loop. You cannot read it after the closing brace. This is a feature — the compiler guarantees you cannot accidentally use a stale counter.
A definite loop says “do something exactly n times.” You reach for for when you know the iteration count up front — a literal, a constant, or a value read from Scanner. The counter variable may never appear in the body at all; its only job is to count.
Quick reference
Syntax
for (init; condition; update) {
// body
}
Evaluation order
init— runs once, before anything else.- Check
condition. Iffalse, exit. - Run
body. - Run
update. - Go back to step 2.
The two canonical “count n times” shapes
for (int i = 0; i < n; i++) { ... } // 0-based: i = 0, 1, ..., n-1 (n passes)
for (int i = 1; i <= n; i++) { ... } // 1-based: i = 1, 2, ..., n (n passes)
Both run the body exactly n times. Pick one and stay consistent. The 0-based form matches how arrays are indexed (week 6).
When to reach for for
Use for whenever you can answer “how many times?” before the loop starts — a literal, a constant, or a value already sitting in a variable. If the count depends on what the body computes (read until a sentinel, search until a hit, repeat until valid), use while instead. The full three-shape decision tree (for / while / do-while) lands in the next lesson.
Update idioms
| Update | Effect | When to use |
|---|---|---|
i++ |
add 1 each step | counting up by 1 |
i-- |
subtract 1 each step | counting down |
i += 2 |
add 2 each step | every other value |
i *= 2 |
double each step | powers of two |
i += k |
add k each step |
custom stride |
Deep dive
1. A first worked example: count 1 to 5
Plan. Print 1, 2, 3, 4, 5 on separate lines using a for loop.
- Counter:
i. - Start:
1. Stop condition: loop whilei <= 5. - Body: print
i. Update:i++.
for (int i = 1; i <= 5; i++) {
System.out.println(i);
}
Trace — notice the update column fires after the body, not before the condition check:
| Check # | i at top |
Action |
|---|---|---|
| 1 | 1 | 1 <= 5 true; print 1; update → i = 2 |
| 2 | 2 | 2 <= 5 true; print 2; update → i = 3 |
| 3 | 3 | 3 <= 5 true; print 3; update → i = 4 |
| 4 | 4 | 4 <= 5 true; print 4; update → i = 5 |
| 5 | 5 | 5 <= 5 true; print 5; update → i = 6 |
| 6 | 6 | 6 <= 5 false; exit |
2. Trace mysteries (the boundary cases)
Mystery 1 — a non-unit stride.
for (int i = 2; i <= 10; i += 3) {
System.out.print(i + " ");
}
System.out.println();
| Check # | i at top |
Action |
|---|---|---|
| 1 | 2 | true; print 2 ; update → 5 |
| 2 | 5 | true; print 5 ; update → 8 |
| 3 | 8 | true; print 8 ; update → 11 |
| 4 | 11 | false; exit |
Output: 2 5 8
The update i += 3 skips i = 9 and i = 10 — the body never sees them because the next check after i = 8 + 3 is 11 <= 10, which is false.
Mystery 2 — a multiplicative update.
for (int n = 1; n <= 16; n *= 2) {
System.out.print(n + " ");
}
System.out.println();
| Check # | n at top |
Action |
|---|---|---|
| 1 | 1 | true; print 1 ; update → 2 |
| 2 | 2 | true; print 2 ; update → 4 |
| 3 | 4 | true; print 4 ; update → 8 |
| 4 | 8 | true; print 8 ; update → 16 |
| 5 | 16 | true; print 16 ; update → 32 |
| 6 | 32 | false; exit |
Output: 1 2 4 8 16
Any expression is valid in the update slot — you are not limited to i++.
3. Loop-variable scope
When you declare the counter in the header, it belongs to the loop. Its scope begins at init and ends at the closing brace of the body. It does not exist outside.
for (int i = 0; i < 3; i++) {
System.out.println("inside: " + i);
}
// System.out.println(i); <-- compile error: cannot find symbol
This is a feature, not a bug. The compiler guarantees the counter cannot be accidentally read or modified after the loop is done. It is also why you can reuse i as the counter name in multiple for loops in the same method without conflict — each loop gets its own fresh i.
Pitfall — using the loop variable after the loop. If you need the counter value after the loop ends (for example, to report how many iterations ran), declare the counter before the header:
int i = 1;on its own line, thenfor (; i <= n; i++)— or just switch to awhile. Inforheaders, the counter dies at the closing brace.
4. The for–while equivalence
A for loop and the matching while loop are mechanically interchangeable. The rewrite has three steps: move the init above, put the condition in the while header, move the update to the end of the body.
// for version
for (int i = 1; i <= 5; i++) {
System.out.println(i);
}
// equivalent while version
int i = 1; // init, moved up
while (i <= 5) { // condition, unchanged
System.out.println(i);
i++; // update, moved to end of body
}
How to pick the shape. If you can answer “how many times?” before the loop starts, use
for— it puts the count management in one place. If the stopping condition depends on what the body computes (sentinel, search, Collatz), usewhile— the body decides, and there is no tidy “count” to put in a header.
for (int i = 10; i > 0; i -= 3) {
System.out.print(i + " ");
}1, the update i -= 3 produces i = -2. The next check -2 > 0 is false, and the loop exits — before the body prints -2. The condition is checked before each pass, not after. The update fires, but its value is only used by the next condition check.
5. The definite loop — do something exactly n times
This is the basic definite for loop: the counter’s only job is to count iterations. It may not even appear in the body.
Plan. Read a count from the user; print a greeting that many times.
Scanner in = new Scanner(System.in);
System.out.print("How many greetings? ");
int n = in.nextInt();
for (int i = 0; i < n; i++) {
System.out.println("Hello!");
}
For input 3, output is three lines of Hello!. For input 0, the condition 0 < 0 is false at entry — the body runs zero times and nothing prints. That is correct behavior, not a bug.
The 0-based form for (int i = 0; i < n; i++) is conventional in Java. It runs the body for i taking values 0, 1, 2, ..., n-1, which is exactly n iterations. This is also the shape that matches array indexing, which is why you will see it everywhere once we reach arrays in week 6.
Counter that prints its own value. The counter can appear in the body — this is not a separate pattern, just a common use.
for (int i = 1; i <= n; i++) {
System.out.print(i + " ");
}
System.out.println();
For n = 5, output is 1 2 3 4 5 (with a trailing space; we fix the trailing separator in lesson 4-e’s fencepost section).
Definite loop, things that go wrong:
- Off by one.
i <= nwith a 0-based start givesn+1iterations, notn. Decide once and stay consistent.- Body accidental use of counter. Ask: should the body see the counter, or just run
ntimes? If the answer is “just runntimes,” the body should not readi.- Negative
n. Withfor (int i = 0; i < n; i++), a negativenproduces zero iterations. Usually that is the right behavior; if the spec demands at least one iteration, add a precondition check before the loop (lesson 3-c).
6. One note on a Python comparison (CSCD 110)
In Python you write for i in range(n): and the language generates each i for you. In Java, the three-part header is explicit: you declare i, you write the stopping condition, you write how i changes. More typing, more control.
for (int i = 0; i < 5; i++) {
System.out.println(i); // 0, 1, 2, 3, 4
}
The Python for i in range(5) counts the same range. Java’s three-part form makes it easy to start at any value, step by any amount, and count up or down.
Before you leave
A for loop packages init, condition, and update into one header; use it when the count is known up front. The body may see the counter or ignore it entirely — that choice defines whether you are using the definite loop in its pure form. Tomorrow we move from counting iterations to collecting something across them: the accumulator pattern, plus the sentinel pattern for loops where you do not know the count in advance.
Note — there is also a
for-eachform. Java has a secondforsyntax,for (int x : array) { ... }, used to visit every element of an array or collection. It comes up in week 6 once arrays exist; for now, use the three-part header above.
Want to practice? The Week 4 quiz-prep set on the practice platform has for traces with non-unit strides and boundary-case mysteries.