Loop Patterns and Debugging
Fencepost, sentinel, accumulators, and the five common loop bugs
After this lesson, you will be able to:
- Apply the six essential loop patterns: counter, accumulator, product, max, min, and flag
- Use
do-whileloops for input validation - Recognize and fix the five most common loop bugs
- Debug loops with print statements and trace tables
- Solve the fencepost problem with the “one outside, rest inside” pattern
The Pattern Behind Every Loop
Lesson 1.4 taught you for, while, and do-while syntax. But knowing how to write a loop is not the same as knowing what pattern to use inside it. Every practical loop follows one of six patterns — and once you recognize them, you will stop writing loops from scratch and start adapting templates.
From CSCD 110: In Python, you wrote
count = 0thencount += 1inside a loop. Java’s loop patterns work identically — initialize a variable, loop through data, update the variable each iteration. The pattern is universal; only the syntax changes.
The Six Essential Loop Patterns
Pattern 1: Counter
Count how many items satisfy a condition. Initialize to 0, increment by 1 when the condition is met:
int count = 0;
for (int i = 1; i <= 100; i++) {
if (i % 7 == 0) {
count++;
}
}
System.out.println("Divisible by 7: " + count); // 14
Pattern 2: Accumulator (Sum)
Maintain a running total. Initialize to 0, add the value each iteration:
int sum = 0;
for (int i = 1; i <= 100; i++) {
if (i % 2 == 0) {
sum += i;
}
}
System.out.println("Sum of evens: " + sum); // 2550
Pattern 3: Product Accumulator
Maintain a running product. Initialize to 1 (not 0!):
int product = 1;
for (int i = 1; i <= 6; i++) {
product *= i;
}
System.out.println("6! = " + product); // 720
Common Pitfall: Never initialize a product accumulator to 0. Anything times 0 is 0 — the result would always be 0. The identity for multiplication is 1, just as the identity for addition is 0.
Pattern 4: Find Maximum
Track the largest value seen. Initialize to Integer.MIN_VALUE:
int max = Integer.MIN_VALUE;
for (int i = 0; i < n; i++) {
int value = scanner.nextInt();
if (value > max) {
max = value;
}
}
Pattern 5: Find Minimum
Track the smallest value seen. Initialize to Integer.MAX_VALUE:
int min = Integer.MAX_VALUE;
for (int i = 0; i < n; i++) {
int value = scanner.nextInt();
if (value < min) {
min = value;
}
}
Pattern 6: Search / Flag
Determine whether any item meets a condition. Initialize a boolean to false:
boolean foundNegative = false;
for (int i = 0; i < n; i++) {
int value = scanner.nextInt();
if (value < 0) {
foundNegative = true;
}
}
if (foundNegative) {
System.out.println("At least one negative number found.");
}
The ZOM-FMF Initialization Guide
How do you remember the correct starting value? Use ZOM-FMF:
| Letter | Initialize To | Patterns |
|---|---|---|
| Zero | 0 |
Counter, Accumulator (sum) |
| One | 1 |
Product accumulator |
| MAX for min | Integer.MAX_VALUE |
Find minimum |
| MIN for max | Integer.MIN_VALUE |
Find maximum |
| First value | first input | Alternative to MAX/MIN |
| False | false |
Search / flag |
A loop computes the factorial of n (the product of all integers from 1 to n). What should the accumulator be initialized to?
do-while for Input Validation
The do-while loop checks its condition after the body, guaranteeing at least one execution. This is perfect for input validation — you must prompt at least once:
Scanner scanner = new Scanner(System.in);
int score;
do {
System.out.print("Enter score (0-100): ");
score = scanner.nextInt();
if (score < 0 || score > 100) {
System.out.println("Invalid. Try again.");
}
} while (score < 0 || score > 100);
System.out.println("Score accepted: " + score);
| Loop | Checks Condition | Minimum Runs | Best For |
|---|---|---|---|
while |
Before body | 0 | Unknown iteration count |
for |
Before body | 0 | Known iteration count |
do-while |
After body | 1 | “Do first, then check” |
Common Pitfall: Don’t forget the semicolon after
while (condition);in a do-while. It is the only loop that ends with a semicolon.
The Fencepost Problem
Print the numbers 1 through 5 separated by commas: 1, 2, 3, 4, 5
A naive loop produces a trailing comma:
for (int i = 1; i <= 5; i++) {
System.out.print(i + ", ");
}
// Output: 1, 2, 3, 4, 5, ← trailing comma!
The fencepost pattern handles the first (or last) item outside the loop:
System.out.print(1); // first post
for (int i = 2; i <= 5; i++) {
System.out.print(", " + i); // fence + post
}
// Output: 1, 2, 3, 4, 5 ← correct!
Key Insight: The name “fencepost” comes from the fact that a fence with N sections needs N+1 posts. When you have N items and N-1 separators, print one item outside the loop and loop the remaining N-1 items with separators.
The Five Most Common Loop Bugs
| # | Bug | Symptom | Fix |
|---|---|---|---|
| 1 | Off-by-one | Loop runs one too many/few times | Check < vs <=, start value |
| 2 | Infinite loop | Program hangs | Verify update moves toward termination |
| 3 | Wrong update | Wrong values, but terminates | Check sum += i vs sum = i |
| 4 | Wrong condition | Stops too early or too late | Read condition aloud |
| 5 | Wrong initialization | First iteration wrong | Use ZOM-FMF |
Debugging with Print Statements
When a loop produces wrong output, add println inside the loop to watch variables change:
int sum = 0;
for (int i = 1; i <= 5; i++) {
sum = i; // BUG: should be sum += i
System.out.println("DEBUG: i=" + i + " sum=" + sum);
}
System.out.println("Sum: " + sum);
Output reveals the bug — sum is being replaced each iteration instead of accumulated:
DEBUG: i=1 sum=1
DEBUG: i=2 sum=2
DEBUG: i=3 sum=3
DEBUG: i=4 sum=4
DEBUG: i=5 sum=5
Sum: 5
The Trick: Print debugging workflow: (1) Observe the wrong output. (2) Add
printlninside the loop showing key variables. (3) Compare actual values to expected values. (4) The first iteration where they diverge reveals the bug. (5) Remove debug prints after fixing.
This code should print numbers 1 through 10, but prints 1 through 9. What is the bug?
for (int i = 1; i < 10; i++) { System.out.println(i); }
Complete Example: Statistics in One Pass
This program combines counter, accumulator, max, and min patterns in a single loop:
import java.util.Scanner;
public class Statistics {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("How many numbers? ");
int n = scanner.nextInt();
int count = 0;
int sum = 0;
int max = Integer.MIN_VALUE;
int min = Integer.MAX_VALUE;
for (int i = 0; i < n; i++) {
System.out.print("Enter number " + (i + 1) + ": ");
int value = scanner.nextInt();
count++;
sum += value;
if (value > max) { max = value; }
if (value < min) { min = value; }
}
System.out.println("Count: " + count);
System.out.println("Sum: " + sum);
System.out.printf("Average: %.2f%n", (double) sum / count);
System.out.println("Max: " + max);
System.out.println("Min: " + min);
}
}
Sample run:
How many numbers? 4
Enter number 1: 85
Enter number 2: 92
Enter number 3: 78
Enter number 4: 95
Count: 4
Sum: 350
Average: 87.50
Max: 95
Min: 78
You want to print A-B-C-D-E (letters separated by dashes). Which approach correctly avoids a trailing dash?
Summary
Every loop follows one of six patterns: counter (count items), accumulator (running total), product (running multiplication), max (track largest), min (track smallest), and flag (search for a condition). Use ZOM-FMF to remember initial values.
The do-while loop guarantees at least one iteration — ideal for input validation where you must prompt before checking.
The fencepost problem arises when you need N items with N-1 separators. Solve it by handling the first (or last) item outside the loop.
The five common loop bugs are off-by-one, infinite loop, wrong update, wrong condition, and wrong initialization. Debug with print statements inside the loop to watch variables change.
Next lesson: Method design patterns — decomposition, overloading, and scope rules for building well-structured programs.