Lesson 12 min

for-in, break & continue

00:00 / 00:00

for-in, break & continue

Now that you know the basic loops, let's explore Dart's cleaner for-in loop for iterating collections, and two essential control keywords — break (exit the loop early) and continue (skip the current iteration).


🔹 The for-in Loop

The for-in loop is designed specifically for iterating over any iterable — List, Set, Map, String, Range, or custom iterables.

Syntax:

dart
for (var element in iterable) { // use element }
dart
void main() { List<String> fruits = ['Apple', 'Banana', 'Cherry', 'Mango']; for (var fruit in fruits) { print(fruit); } }

Output:

Apple
Banana
Cherry
Mango

Much cleaner than for (int i = 0; i < fruits.length; i++) when you don't need the index!

Iterating a Set

dart
void main() { Set<int> primes = {2, 3, 5, 7, 11, 13}; for (var prime in primes) { print('$prime is prime'); } }

Iterating a Map

For a Map, for-in gives you each MapEntry:

dart
void main() { Map<String, int> scores = { 'Alice': 92, 'Bob': 85, 'Charlie': 78, }; // Iterate entries for (var entry in scores.entries) { print('${entry.key}: ${entry.value}'); } // Iterate only keys for (var name in scores.keys) { print(name); } // Iterate only values for (var score in scores.values) { print(score); } }

Iterating a String

In Dart, a String is an iterable of characters:

dart
void main() { String word = 'Dart'; for (var char in word.split('')) { print(char); } }

Output:

D
a
r
t

🔹 for-in vs forEach()

Both let you iterate a collection, but they have important differences:

dart
void main() { List<int> numbers = [1, 2, 3, 4, 5]; // for-in for (var n in numbers) { print(n); } // forEach() with lambda numbers.forEach((n) => print(n)); }
Aspectfor-inforEach()
break support✅ Yes❌ No
continue support✅ Yes❌ No
return exits function✅ Yes❌ Only exits lambda
await inside✅ Works naturally⚠️ Needs asyncForEach workaround
ReadabilityExcellentGood for simple transforms

Tip: Prefer for-in over forEach() in most cases. It supports break, continue, and return as expected. Use forEach() only for simple one-liner callbacks.


🔹 break — Exit the Loop

break immediately stops the loop and resumes execution after the closing }.

dart
void main() { List<int> numbers = [4, 7, 2, 9, 1, 6, 3]; int target = 9; int foundAt = -1; for (int i = 0; i < numbers.length; i++) { if (numbers[i] == target) { foundAt = i; break; // Stop searching — we found it! } } if (foundAt >= 0) { print('Found $target at index $foundAt'); } else { print('$target not found'); } }

Output: Found 9 at index 3

Without break, the loop would continue pointlessly even after finding the target.

break in a while Loop

dart
void main() { int n = 1; while (true) { // intentional "infinite" loop if (n * n > 100) { break; // exit when n² exceeds 100 } n++; } print('Largest n where n² <= 100: ${n - 1}'); // 10 }

🔹 continue — Skip the Current Iteration

continue skips the rest of the current iteration and jumps to the next one.

dart
void main() { List<int> numbers = [-3, 7, -1, 5, -8, 2, 4]; print('Positive numbers only:'); for (var n in numbers) { if (n < 0) { continue; // Skip negative numbers } print(n); } }

Output:

Positive numbers only:
7
5
2
4

continue in a for Loop

dart
void main() { // Print all numbers 1–20, skip multiples of 3 for (int i = 1; i <= 20; i++) { if (i % 3 == 0) { continue; } stdout.write('$i '); } print(''); }

Output: 1 2 4 5 7 8 10 11 13 14 16 17 19 20


🔹 Labels for Nested Loops

When you have nested loops, break and continue by default only affect the innermost loop. Use labels to control an outer loop.

dart
void main() { // Without label: break only exits inner loop for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (j == 1) break; // only breaks inner loop print('($i, $j)'); } } }

Output:

(0, 0)
(1, 0)
(2, 0)

Labeled break — Exit Outer Loop

dart
void main() { outerLoop: // label for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (i == 1 && j == 1) { print('Breaking out of both loops at ($i, $j)'); break outerLoop; // breaks the OUTER loop } print('($i, $j)'); } } print('Done.'); }

Output:

(0, 0)
(0, 1)
(0, 2)
(1, 0)
Breaking out of both loops at (1, 1)
Done.

Labeled continue — Skip to Next Outer Iteration

dart
void main() { outerLoop: for (int i = 1; i <= 3; i++) { for (int j = 1; j <= 3; j++) { if (j == 2) { continue outerLoop; // skip to next i } print('($i, $j)'); } } }

Output:

(1, 1)
(2, 1)
(3, 1)

Note: Labeled breaks are powerful but can make code hard to follow. Consider refactoring into a function with return for cleaner logic.


🔹 Real-World Examples

Example 1: Find First Match

dart
String? findFirstAdult(List<Map<String, dynamic>> users) { for (var user in users) { if (user['age'] >= 18) { return user['name']; // return also exits the loop } } return null; } void main() { List<Map<String, dynamic>> users = [ {'name': 'Tom', 'age': 15}, {'name': 'Lisa', 'age': 22}, {'name': 'Mark', 'age': 19}, ]; String? firstAdult = findFirstAdult(users); print('First adult: $firstAdult'); // First adult: Lisa }

Example 2: Skip Negative Numbers, Sum the Rest

dart
void main() { List<int> data = [10, -3, 25, -8, 4, -1, 17, 6]; int sum = 0; int skipped = 0; for (var n in data) { if (n < 0) { skipped++; continue; } sum += n; } print('Sum of positives: $sum'); // Sum of positives: 62 print('Negative values skipped: $skipped'); // Negative values skipped: 3 }

Example 3: Process Until Condition Met

dart
void main() { List<String> tasks = [ 'init_database', 'load_config', 'connect_server', 'ERROR_TIMEOUT', // Simulate an error task 'start_app', 'send_report', ]; print('Processing tasks:'); for (var task in tasks) { if (task.startsWith('ERROR')) { print('❌ Error encountered: $task — stopping.'); break; } print('✅ Completed: $task'); } }

Output:

Processing tasks:
✅ Completed: init_database
✅ Completed: load_config
✅ Completed: connect_server
❌ Error encountered: ERROR_TIMEOUT — stopping.

Example 4: Collect Valid Emails Only

dart
bool isValidEmail(String email) { return email.contains('@') && email.contains('.'); } void main() { List<String> rawEmails = [ 'alice@example.com', 'invalid-email', 'bob@test.org', 'noatsign', 'charlie@domain.net', ]; List<String> validEmails = []; for (var email in rawEmails) { if (!isValidEmail(email)) { print('Skipping invalid: $email'); continue; } validEmails.add(email); } print('\nValid emails: $validEmails'); }

Output:

Skipping invalid: invalid-email
Skipping invalid: noatsign

Valid emails: [alice@example.com, bob@test.org, charlie@domain.net]

Summary

FeatureKeywordPurpose
For-in loopfor (var x in iterable)Cleanly iterate any iterable
Exit a loopbreakStop the loop immediately
Skip iterationcontinueSkip rest of current iteration, go to next
Exit outer loopbreak labelNameBreak out of a specific outer loop
Skip outer iterationcontinue labelNameContinue on a specific outer loop

With for-in, break, and continue in your toolkit, you can write expressive, efficient loops. Up next: functions — the building blocks of reusable code!

WhatsApp