When a Plain Loop Wins
The four jobs where a for loop is still the clearer, faster and more honest answer.
Open this lesson in the learning hubKey points
- You need the index.
IntStream.range(...).mapToObj(i -> list.get(i))is a stream pretending to be a loop. - You are filling two collections at once. One loop does it in one pass; the stream version needs teeing or two passes.
- You want to break early while keeping running state.
breakis one word; the stream needs takeWhile plus a fold. - You are mutating the source, or the body throws checked exceptions. Neither fits comfortably in a lambda.
- Streams win on straight transform, filter and aggregate work. Mixed responsibilities usually read better as a loop.
- Never nest three streams deep to avoid a loop. Reviewers read the loop faster, and so will you next quarter.
Example
import java.util.*;
import java.util.stream.*;
public class Main {
public static void main(String[] args) {
List<String> rows = List.of("ada", "grace", "alan", "edsger");
// 1. You need the index. The stream version has to invent one.
StringBuilder numbered = new StringBuilder();
for (int i = 0; i < rows.size(); i++) {
numbered.append(i + 1).append('.').append(rows.get(i)).append(' ');
}
System.out.println("loop index : " + numbered.toString().trim());
System.out.println("faked index : " + IntStream.range(0, rows.size())
.mapToObj(i -> (i + 1) + "." + rows.get(i)).collect(Collectors.joining(" ")));
// 2. You are filling two collections in one pass.
List<String> shortNames = new ArrayList<>();
List<String> longNames = new ArrayList<>();
for (String r : rows) {
(r.length() <= 4 ? shortNames : longNames).add(r);
}
System.out.println("two lists : " + shortNames + " " + longNames);
// 3. Stop early and keep a running total. break is plain; the stream needs two steps.
int total = 0;
for (String r : rows) {
if (r.startsWith("e")) {
break;
}
total += r.length();
}
System.out.println("loop total : " + total);
System.out.println("stream same : " + rows.stream()
.takeWhile(r -> !r.startsWith("e")).mapToInt(String::length).sum());
}
}
A stream is a tool, not a style rule. Pick whichever one the next reader will understand faster.
This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Streams course, and every lesson in it is listed on the Streams contents page.