Convert me a Java for-loop with break (find the first item over a threshold) into the equivalent EK9 stream pipeline.
← Control Flow Without break/continue/return · Ref: Q1239
EK9 has no break statement, so loops with early exit on first match are expressed as a stream pipeline using filter + head. The pipeline is more declarative AND eliminates the loop variable that Java needed.
THE JAVA PATTERN
Integer firstBig = null; for (Integer n : numbers) { if (n > 50) { firstBig = n; break; } } if (firstBig != null) System.out.println(firstBig);
Three problems: a mutable accumulator, a break statement, and a null check. EK9 eliminates all three.
THE EK9 STREAM EQUIVALENT
Use filter to keep only matching items, then head to take the first one, then collect into a List:
isBig() as pure -> n as Integer <- big as Boolean: n > 50
firstBig <- cat numbers | filter by isBig | head 1 | collect as List of Integer
The pipeline reads top-to-bottom: 'cat' streams the list, 'filter' keeps matches, 'head 1' takes the first, 'collect' produces a final List. There is no loop variable, no mutable accumulator, no break.
USAGE
numbers <- [10, 25, 60, 75, 90] firstBig <- cat numbers | filter by isBig | head 1 | collect as List of Integer if firstBig? stdout.println(`First > 50: ${firstBig}`)
WHY EK9 PREFERS THIS
1. No break — loop control is implicit in the pipeline.
2. No mutable accumulator — the result is an expression.
3. The filter predicate is reusable and unit-testable on its own.
4. Adding 'sort' or 'map' is one more pipe stage, not a refactor.
See Q284 for find-first via guarded assignment. See Q288 for migrating break loops. See Q142 for stream pipeline basics.
Example
defines module qa.without.streamfindfirst defines constant BIG_THRESHOLD <- 50 defines function isBig() as pure -> n as Integer <- big as Boolean: n > BIG_THRESHOLD defines program MigrateBreakDemo() stdout <- Stdout() numbers <- [10, 25, 60, 75, 90] firstBig <- cat numbers | filter by isBig | head 1 | collect as List of Integer if firstBig? stdout.println(`First > ${BIG_THRESHOLD}: ${firstBig}`)
Common mistakes
E01070 — EK9 has no 'break' statement. Use a stream pipeline with 'filter | head 1' to take only the first match, eliminating the need for early loop exit. See ek9 -h E01070 for details.
Incorrect:
for n in numbers if n > 50 firstBig: n break
Correct:
firstBig <- cat numbers | filter by isBig | head 1 | collect as List of Integer
Other ways to ask this
- Migrate a Java for/break loop to EK9 without using break.
- Show me how to replace 'for + break on first match' with an EK9 stream.
- Rewrite a Java early-exit loop in idiomatic EK9.
- How do I express 'find first over N' without a loop in EK9?
Coming from another language?
Java: for + break, or stream().filter().findFirst().orElse(null). Python: next((x for x in items if predicate(x)), None). Kotlin: items.firstOrNull { predicate(it) }. Rust: items.iter().find(|x| predicate(x)). Go: explicit for loop with break. EK9: 'cat items | filter by predicate | head 1 | collect as List of T' — explicit pipeline without break and without nullable return.
Keywords: migration, break, Java to EK9, stream, without break, head, filter, find first, early exit