Definition
Four loop constructs:
- for: Best when you know the iteration count or need an index.
for (int i = 0; i < n; i++). - for-each: Best for iterating arrays and collections without an index.
for (Account a : accounts). - while: Condition checked before each iteration. The body may never run.
while (scanner.hasNext()). - do-while: Body runs at least once, condition checked after.
do { retry(); } while (!success).
A bank teller processing a queue. The for loop says: "Process exactly 10 customers." The for-each says: "Process every customer in the queue." The while says: "Keep processing while there are customers waiting." The do-while says: "Process at least one customer, then check if more are waiting."
Understanding the Concepts
How does the for loop work?
// Process the first 5 transactions
for (int i = 0; i < 5; i++) {
System.out.println("Processing transaction " + (i + 1));
}
// Multiple variables in for loop
for (int i = 0, j = 10; i < j; i++, j--) {
System.out.println(i + " " + j);
}
How does for-each work?
List<Account> accounts = getActiveAccounts();
for (Account account : accounts) {
System.out.println(account.getAccountId() + ": " + account.getBalance());
}
// Works with arrays too
int[] amounts = {50000, 12000, 8000};
for (int amount : amounts) {
total += amount;
}
for-each is cleaner but you cannot modify the collection or access the index. Use a traditional for loop when you need either.
How does while work?
// Read transactions until end of file
BufferedReader reader = new BufferedReader(new FileReader("transactions.csv"));
String line;
while ((line = reader.readLine()) != null) {
processTransaction(line);
}
How does do-while work?
// Retry a transfer until it succeeds or max retries reached
int attempts = 0;
boolean success;
do {
success = attemptTransfer(from, to, amount);
attempts++;
} while (!success && attempts < 3);
The body always runs at least once. Use when you need to execute before checking the condition.
How do break and continue work?
// break: exit the loop entirely
for (Account account : accounts) {
if (account.isFrozen()) {
System.out.println("Frozen account found: " + account.getAccountId());
break; // stop searching
}
}
// continue: skip to the next iteration
for (Account account : accounts) {
if (!account.isActive()) {
continue; // skip inactive accounts
}
processAccount(account);
}
What about labeled break for nested loops?
outer:
for (String branch : branches) {
for (Account account : getAccounts(branch)) {
if (account.getAccountId().equals(targetId)) {
System.out.println("Found in branch: " + branch);
break outer; // exits BOTH loops
}
}
}
What about infinite loops?
// Common patterns for servers and event loops
while (true) {
Request request = server.accept();
processRequest(request);
}
for (;;) { // equivalent to while(true)
// ...
}
When should you use which loop?
| Loop | Use when |
|---|---|
| for | Known count, need index, multiple control variables |
| for-each | Iterating collection/array, no index needed |
| while | Unknown iterations, condition-first check |
| do-while | Must execute at least once (retry logic, menu prompts) |
What are common mistakes?
- Off-by-one errors.
for (int i = 0; i <= n; i++)runs n+1 times. Use< nfor n iterations. - Modifying collection in for-each.
accounts.remove(account)during for-each throwsConcurrentModificationException. UseIterator.remove()orremoveIf(). - Infinite loop without exit. Forgetting to update the condition variable in while. Always ensure progress toward termination.
- Using while when for is clearer. If you have init, condition, and update, use for to keep them in one line.
What should a senior engineer know?
- Streams replace many loops.
accounts.stream().filter(Account::isActive).forEach(this::process)is often cleaner than a for-each with continue. - Parallel streams for CPU-bound work.
accounts.parallelStream().map(...)distributes across cores. But avoid for I/O-bound or side-effect-heavy operations. - Loop unrolling is done by the JIT. You do not need to manually unroll loops. The C2 compiler handles it.
- for-each works with any Iterable. Your custom collection class just needs to implement
Iterableto work with for-each.
Visual Overview
for (init; condition; update) for (T item : collection)
init → check → body → update iterator → hasNext? → body → next
→ check → body → update → ... → hasNext? → body → next → ...
while (condition) do { body } while (condition)
check → body → check → ... body → check → body → check → ...
(may never run) (always runs at least once)
break: exits the loop entirely
continue: skips to the next iteration
break label: exits the labeled outer loop
Key Takeaway
Java has four loop constructs. The for loop is best when you know the iteration count or need an index. The for-each loop is cleanest for iterating collections and arrays. The while loop checks the condition first and may never execute the body. The do-while loop always executes the body at least once, then checks.
Break exits the loop entirely. Continue skips to the next iteration. Labeled break exits a named outer loop from inside a nested inner loop.
One sentence to remember: use for when you have a counter, for-each when you have a collection, while when you have a condition, and do-while when the body must run at least once.
---