A loop is how you repeat work — running every test case in a list, retrying a flaky API call until it succeeds, walking every row of a result table. Java has four loop constructs: the classic for, the while, the rarely-seen do/while, and the enhanced for loop (also called for-each). They all do the same family of jobs; choosing the right one is mostly about reading clarity. This lesson works through all four with QA scenarios you'll meet on day one.
The classic for loop
public class BrowserMatrix {
public static void main(String[] args) {
String[] browsers = {"Chrome", "Firefox", "Safari", "Edge"};
for (int i = 0; i < browsers.length; i++) {
System.out.println("Testing on: " + browsers[i]);
}
}
}Output:
Testing on: Chrome
Testing on: Firefox
Testing on: Safari
Testing on: Edge
Three semicolon-separated parts inside the parentheses:
- Initialisation:
int i = 0— runs once at the start. - Condition:
i < browsers.length— checked before each iteration; loop ends when this is false. - Update:
i++— runs after each iteration. (i++is shorthand fori = i + 1.)
The body is everything between the braces. This shape is identical to JavaScript's for loop, including the < length (not <= length) bound — arrays are zero-indexed, so the last valid index is length - 1.
while — when the count isn't known
while repeats as long as a condition is true. Use it when you don't know in advance how many iterations you'll need.
public class FlakyRetry {
public static void main(String[] args) {
int attempt = 0;
boolean succeeded = false;
while (attempt < 3 && !succeeded) {
attempt++;
System.out.println("Attempt " + attempt);
// pretend the third attempt finally works
if (attempt == 3) succeeded = true;
}
System.out.println(succeeded ? "Test passed after " + attempt : "Gave up");
}
}Output:
Attempt 1
Attempt 2
Attempt 3
Test passed after 3
while evaluates the condition before the body. If the condition is false on the first check, the body never runs. The combined attempt < 3 && !succeeded is the typical retry shape — bounded retries that exit early on success.
do / while — runs at least once
do/while flips the order: body first, then condition. The body always runs at least once.
public class PollUntilReady {
public static void main(String[] args) {
int retries = 0;
int statusCode;
do {
statusCode = checkHealth(); // pretend method
retries++;
System.out.println("Attempt " + retries + " -> status " + statusCode);
} while (statusCode != 200 && retries < 5);
}
static int checkHealth() {
// simulate the service coming up on the second poll
return Math.random() < 0.5 ? 503 : 200;
}
}You'll see this shape in health-check polling — you always want to try once before deciding whether to retry. In modern Java code do/while is rare; most teams use a regular while with the call inside.
Enhanced for loop (for-each) — the cleanest version
When you don't actually need the index, the enhanced for loop is shorter and harder to get wrong:
public class RunAllTests {
public static void main(String[] args) {
String[] testCases = {"Login", "Search", "Checkout", "Logout"};
for (String testCase : testCases) {
System.out.println("Running: " + testCase);
}
}
}Output:
Running: Login
Running: Search
Running: Checkout
Running: Logout
Read the line for (String testCase : testCases) as: "for each testCase in testCases." This is Java's equivalent of JavaScript's for...of and Python's for x in xs. It works on any array or anything that implements Iterable — which means every List, Set, or Queue you'll meet in chapter 6.
When to use which:
- Indexed
for— when you need the index (i), or when you need to walk in reverse, or when you'll skip by 2 (i += 2). - Enhanced for — when you just need each element. About 80% of the loops in real test code.
while— when the loop condition isn't simply "I haven't hit the end yet" — retries, polling, reading a stream until EOF.do/while— almost never; only when the body has to run at least once before checking.
Counting test results
A common QA snippet — count passes and failures across an array of booleans:
public class ResultTally {
public static void main(String[] args) {
boolean[] results = {true, true, false, true, false, true};
int passed = 0;
int failed = 0;
for (boolean result : results) {
if (result) passed++;
else failed++;
}
int total = passed + failed;
double passRate = (passed * 100.0) / total;
System.out.println("Passed: " + passed);
System.out.println("Failed: " + failed);
System.out.println("Pass rate: " + passRate + "%");
}
}Output:
Passed: 4
Failed: 2
Pass rate: 66.66666666666667%
The pattern — accumulate a counter inside a loop — is the entire shape of every test summary you'll ever write. Replace boolean[] with a list of TestResult objects and you're 90% of the way to a real reporter.
Stepping through a for loop
Step 1 of 6
Initialise
int i = 0; — the loop counter starts at zero. The array has 4 elements, indices 0..3.
That six-step cycle — init, check, run, update, check, run, …, exit — is the engine inside every classic for loop. Once you've internalised it, the same shape covers every variation.
⚠️ Common mistakes
- Off-by-one in the bound.
for (int i = 0; i <= arr.length; i++)reads one past the end of the array — the last access throwsArrayIndexOutOfBoundsException. The fix is<not<=. Or just use the enhanced for loop and dodge the issue entirely. - Modifying the loop variable accidentally.
for (String case : cases) { case = case.trim(); ... }reassigns the localcasevariable, but does not change the array. If you need to mutate the array, use the indexed form:cases[i] = cases[i].trim();. - Infinite loop from a forgotten
++.while (attempt < 3) { runTest(); }with noattempt++runs forever. Forgetting the update is the most common cause of a hanging test. If your test "freezes," check the loop's exit condition.
🎯 Practice task
Build a test matrix runner. 25-30 minutes.
- Create
MatrixRunner.java. - Declare three arrays:
String[] browsers = {"Chrome", "Firefox", "Safari"};boolean[] results = {true, false, true, true, false, true, true, true};int[] retries = {0, 0, 0};
- Use a classic for loop to print each browser with its 1-based index, e.g.
1. Chrome,2. Firefox,3. Safari. (You need the index for the numbering.) - Use an enhanced for loop to walk
resultsand tallypassedandfailedcounters. Print the totals and pass rate. - Use a while loop to simulate retrying a flaky call: start
attempt = 0, increment until eitherattempt == 3or a (faked) success. Print each attempt. - Stretch: combine browsers and a hard-coded
String[] resolutions = {"1920x1080", "1366x768"};to print the full cross-product — 6 lines likeChrome @ 1920x1080. You'll need a loop inside a loop. (Lesson 4 covers this properly — give it a go now anyway.) - Compile (
javac MatrixRunner.java) and run (java MatrixRunner). Confirm the totals match the array contents.
You now have the four loop constructs in your toolkit. The next lesson covers break, continue, and the labelled-break trick that lets you escape from inside nested loops.