| |

Dart 11 ๐ŸŽฏ Loops: for, for-in, while, do-while, and Loop Control (break, continue)

Loops repeat a block of code. Dart provides four loop constructs โ€” for, for-in, while, and do-while โ€” each suited to a different situation. The classic for loop is for counting and index-based iteration. The for-in loop iterates over the elements of a collection. The while loop repeats while a condition is true. The do-while loop executes the body at least once before checking the condition. Loop control statements โ€” break and continue โ€” exit a loop or skip an iteration, and labeled loops allow control flow across nested loops.

The choice among the four constructs is not arbitrary. for-in is the idiomatic way to iterate over a list, set, or map in Dart, and it eliminates the off-by-one errors that come with index-based loops. The classic for loop is appropriate when the index matters or when the iteration count is known. while is for condition-driven repetition. do-while is for cases where the body must run at least once, such as prompting for input until a valid value is entered.

This chapter covers each loop construct, the difference between them, loop control with break and continue, labeled loops for nested iteration, the forEach method as an alternative for collections, and the patterns that make iteration readable and correct.

Key point: Use for-in to iterate over collections, the classic for when the index matters, while for condition-driven repetition, and do-while when the body must run at least once. break exits a loop, continue skips to the next iteration, and labels allow both to target an outer loop. Dart’s for-in over a collection is preferred over index-based iteration.


Why multiple loop constructs exist

The counting problem. Some loops run a known number of times: process the first ten items, generate a multiplication table, iterate from 0 to n. The classic for loop with an index expresses this directly, and the index is available for computations.

The collection problem. Most iteration is over a collection: a list of users, a set of tags, a map of settings. The for-in loop iterates over the elements directly, without an index, and it works with any object that implements Iterable. This is the idiomatic form for collections.

The condition problem. Some loops repeat until a condition changes: read until end of file, retry until success, drain a queue. The while loop checks the condition before each iteration, so the body may run zero times if the condition is initially false.

The at-least-once problem. Some loops must run the body at least once before checking the condition: prompt for input, then validate; attempt an operation, then check success. The do-while loop checks the condition after the body, guaranteeing at least one execution.

The control problem. Inside a loop, it is sometimes necessary to exit early or skip an iteration. break and continue provide this, and labels extend it to nested loops so that an inner loop can break out of an outer one.


a. The classic for loop

The classic for loop has three parts in parentheses: an initializer, a condition, and an update.

for (var i = 0; i < 5; i++) {
  print(i);  // 0, 1, 2, 3, 4
}

The initializer runs once before the loop begins. The condition is checked before each iteration. The update runs after each iteration. When the condition is false, the loop ends.

The index variable is available inside the body, so the classic for is appropriate when the index matters:

var names = ['Alice', 'Bob', 'Carol'];

for (var i = 0; i < names.length; i++) {
  print('${i + 1}. ${names[i]}');  // 1. Alice, 2. Bob, 3. Carol
}

The loop can count in any direction or by any step:

// Count down
for (var i = 5; i > 0; i--) {
  print(i);  // 5, 4, 3, 2, 1
}

// Step by two
for (var i = 0; i < 10; i += 2) {
  print(i);  // 0, 2, 4, 6, 8
}

// Multiple variables
for (var i = 0, j = 10; i < j; i++, j--) {
  print('$i $j');
}

The var i in the initializer is scoped to the loop. After the loop, i is not accessible. Using var is preferred over declaring the variable outside, because it keeps the scope tight.

An infinite for loop is written with an empty condition:

for (;;) {
  // runs forever unless break is used
}

This form is rare; the while (true) form is more readable.


b. The for-in loop

The for-in loop iterates over the elements of an Iterable. It is the idiomatic way to traverse a list, set, or map’s values.

var names = ['Alice', 'Bob', 'Carol'];

for (var name in names) {
  print(name);  // Alice, Bob, Carol
}

Each iteration assigns the next element to the loop variable. The variable is a copy for value types and a reference for objects. Modifying the variable inside the body does not affect the collection.

for (var name in names) {
  name = name.toUpperCase();  // does not change the list
}

The for-in loop works with any Iterable, which includes lists, sets, and the results of iterators and generators. It also works with maps through the .keys, .values, and .entries properties.

var scores = {'Alice': 95, 'Bob': 87};

for (var name in scores.keys) {
  print(name);
}

for (var score in scores.values) {
  print(score);
}

for (var entry in scores.entries) {
  print('${entry.key}: ${entry.value}');
}

The for-in loop is preferred over the classic for with an index because it is shorter, does not require bounds checking, and works with any iterable. The main reason to use the classic for instead is when the index is needed.


c. The while loop

The while loop checks a condition before each iteration. The body runs zero or more times.

var count = 0;

while (count < 5) {
  print(count);  // 0, 1, 2, 3, 4
  count++;
}

If the condition is false initially, the body never runs:

var count = 10;

while (count < 5) {
  print(count);  // never runs
  count++;
}

The while loop is appropriate when the number of iterations is not known in advance and depends on a condition that changes during the loop.

var input = '';
while (input != 'quit') {
  input = readLine();
  process(input);
}

A common mistake is a loop that never terminates because the condition never becomes false. Every while loop must have a path that changes the condition, or it must contain a break.


d. The do-while loop

The do-while loop executes the body first, then checks the condition. The body runs at least once.

var count = 0;

do {
  print(count);  // 0, 1, 2, 3, 4
  count++;
} while (count < 5);

Even if the condition is false initially, the body runs once:

var count = 10;

do {
  print(count);  // prints 10 once
  count++;
} while (count < 5);

The do-while is appropriate when the body must run at least once, such as prompting for input and validating it:

String? input;
do {
  print('Enter a number:');
  input = readLine();
} while (input == null || int.tryParse(input) == null);

The loop runs, reads input, and repeats until the input is a valid number. The first prompt always appears, which is the intent.

A subtle difference: in a do-while, the variables used in the condition must be declared before the loop, because the condition is evaluated after the body.


e. break and continue

The break statement exits the loop immediately. The continue statement skips the rest of the current iteration and proceeds to the next.

for (var i = 0; i < 10; i++) {
  if (i == 5) break;
  print(i);  // 0, 1, 2, 3, 4
}

for (var i = 0; i < 10; i++) {
  if (i % 2 == 0) continue;
  print(i);  // 1, 3, 5, 7, 9
}

break is used to exit early when a condition is met, such as finding the first match in a list:

var numbers = [3, 7, 2, 9, 4];
var found = -1;

for (var i = 0; i < numbers.length; i++) {
  if (numbers[i] == 9) {
    found = i;
    break;
  }
}
print(found);  // 3

continue is used to skip unwanted iterations, such as processing only valid entries:

for (var item in items) {
  if (item == null) continue;
  process(item);
}

Both break and continue apply to the innermost loop that contains them. In nested loops, they affect only the inner loop.


f. Labeled loops

A label is an identifier followed by a colon, placed before a loop. It allows break and continue to target a specific loop, which matters in nested loops.

outer:
for (var i = 0; i < 3; i++) {
  for (var j = 0; j < 3; j++) {
    if (i == 1 && j == 1) {
      break outer;  // exits both loops
    }
    print('$i $j');
  }
}

Without the label, break would exit only the inner loop, and the outer loop would continue. The label makes the intent explicit.

A labeled continue skips to the next iteration of the labeled loop:

outer:
for (var i = 0; i < 3; i++) {
  for (var j = 0; j < 3; j++) {
    if (j == 1) {
      continue outer;  // skips to next i
    }
    print('$i $j');
  }
}

Labels are useful for searching nested structures, breaking out of a matrix traversal, and any case where the exit condition spans multiple loop levels. They should be used sparingly, because they can make control flow harder to follow.


g. forEach and collection methods

Dart collections provide a forEach method that takes a function and applies it to each element.

var names = ['Alice', 'Bob', 'Carol'];

names.forEach((name) {
  print(name);
});

The forEach method is a terminal operation on an iterable. It is equivalent to a for-in loop but does not support break or continue, because it is a function call rather than a loop. Inside a forEach, a return statement exits the closure for that element, but does not exit the iteration. To exit the iteration early, a for-in loop with break is required.

// Cannot break out of forEach
names.forEach((name) {
  if (name == 'Bob') return;  // returns from the closure, not the loop
  print(name);
});

For iteration that needs control flow, for-in is the better choice. forEach is appropriate for simple side effects that apply to every element.

Modern Dart prefers the higher-order methods map, where, reduce, and fold over explicit loops for transformations:

// Map each element
var upper = names.map((name) => name.toUpperCase()).toList();

// Filter elements
var short = names.where((name) => name.length <= 3).toList();

// Aggregate
var total = numbers.reduce((a, b) => a + b);
var sum = numbers.fold<int>(0, (acc, n) => acc + n);

These methods express the intent more directly than a loop and compose with each other. They are covered in their own chapter; the point here is that Dart has idiomatic alternatives to loops for common collection operations.


Complete Example Session

// ============================================
// PART 1: CLASSIC FOR LOOP
// ============================================
void main() {
  for (var i = 0; i < 5; i++) {
    print(i);  // 0, 1, 2, 3, 4
  }
}
// ============================================
// PART 2: COUNT DOWN AND STEP
// ============================================
void main() {
  for (var i = 5; i > 0; i--) {
    print(i);  // 5, 4, 3, 2, 1
  }

  for (var i = 0; i < 10; i += 2) {
    print(i);  // 0, 2, 4, 6, 8
  }
}
// ============================================
// PART 3: FOR-IN OVER A LIST
// ============================================
void main() {
  var names = ['Alice', 'Bob', 'Carol'];

  for (var name in names) {
    print(name);
  }
}
// ============================================
// PART 4: FOR-IN OVER MAP ENTRIES
// ============================================
void main() {
  var scores = {'Alice': 95, 'Bob': 87};

  for (var entry in scores.entries) {
    print('${entry.key}: ${entry.value}');
  }
}
// ============================================
// PART 5: WHILE LOOP
// ============================================
void main() {
  var count = 0;

  while (count < 5) {
    print(count);
    count++;
  }
}
// ============================================
// PART 6: DO-WHILE LOOP
// ============================================
void main() {
  var count = 0;

  do {
    print(count);  // runs at least once
    count++;
  } while (count < 5);
}
// ============================================
// PART 7: BREAK AND CONTINUE
// ============================================
void main() {
  for (var i = 0; i < 10; i++) {
    if (i == 5) break;
    print(i);  // 0, 1, 2, 3, 4
  }

  for (var i = 0; i < 10; i++) {
    if (i % 2 == 0) continue;
    print(i);  // 1, 3, 5, 7, 9
  }
}
// ============================================
// PART 8: FINDING AN ELEMENT WITH BREAK
// ============================================
void main() {
  var numbers = [3, 7, 2, 9, 4];
  var found = -1;

  for (var i = 0; i < numbers.length; i++) {
    if (numbers[i] == 9) {
      found = i;
      break;
    }
  }

  print(found);  // 3
}
// ============================================
// PART 9: LABELED BREAK
// ============================================
void main() {
  outer:
  for (var i = 0; i < 3; i++) {
    for (var j = 0; j < 3; j++) {
      if (i == 1 && j == 1) {
        break outer;
      }
      print('$i $j');
    }
  }
  // (0,0), (0,1), (0,2), (1,0)
}
// ============================================
// PART 10: FOR-IN WITH COLLECTION METHODS
// ============================================
void main() {
  var numbers = [1, 2, 3, 4, 5];

  // Classic iteration
  for (var n in numbers) {
    print(n);
  }

  // Functional alternative
  var doubled = numbers.map((n) => n * 2).toList();
  var evens = numbers.where((n) => n % 2 == 0).toList();
  var sum = numbers.fold<int>(0, (acc, n) => acc + n);

  print(doubled);  // [2, 4, 6, 8, 10]
  print(evens);    // [2, 4]
  print(sum);      // 15
}

These ten parts cover the classic for loop, counting down and stepping, for-in over a list, for-in over map entries, the while loop, the do-while loop, break and continue, finding an element with break, labeled break, and the functional alternatives.


Quick Reference

Loop Constructs

LoopChecksRuns BodyBest For
forBefore each0+ timesCounting, index matters
for-inEach elementOnce per elementCollections
whileBefore each0+ timesCondition-driven
do-whileAfter each1+ timesAt-least-once

for Loop Syntax

PartExample
Initializervar i = 0
Conditioni < 5
Updatei++
Fullfor (var i = 0; i < 5; i++)

for-in Syntax

FormExample
Listfor (var x in list)
Setfor (var x in set)
Map keysfor (var k in map.keys)
Map valuesfor (var v in map.values)
Map entriesfor (var e in map.entries)

Loop Control

StatementEffect
breakExit the loop
continueSkip to next iteration
break labelExit labeled loop
continue labelContinue labeled loop

Functional Alternatives

MethodPurpose
forEachApply function to each element
mapTransform each element
whereFilter elements
reduceAggregate to a single value
foldAggregate with initial value

Best Practices

โœ… Do This:

// for-in for collections
for (var name in names) { print(name); }

// Classic for when index is needed
for (var i = 0; i < names.length; i++) { print('$i: ${names[i]}'); }

// do-while for at-least-once
do { input = readLine(); } while (input == null);

// break to exit early
if (found) break;

// continue to skip
if (item == null) continue;

โŒ Don’t Do This:

// Index loop when for-in works
for (var i = 0; i < names.length; i++) { print(names[i]); }  // โŒ use for-in

// forEach when break is needed
names.forEach((n) { if (n == 'x') return; });  // โŒ use for-in with break

// Mutating collection during iteration
for (var n in list) { list.remove(n); }  // โŒ ConcurrentModificationError

// Unlabeled break in nested loops
for (...) { for (...) { break; } }  // โŒ only exits inner

Common Pitfalls

PitfallWhy It HappensFix
Infinite loopCondition never falseEnsure the condition changes
Concurrent modificationModifying list during iterationIterate over a copy
continue in forEachforEach is not a loopUse for-in
break exits only innerNested loopsUse a label
Off-by-one<= instead of <Use < for length
do-while variable scopeCondition needs the variableDeclare before the loop

Real-World Examples

1. Count Up

for (var i = 0; i < 10; i++) {
  print(i);
}

2. Count Down

for (var i = 10; i > 0; i--) {
  print(i);
}

3. Iterate a List

for (var item in items) {
  process(item);
}

4. Iterate Map Entries

for (var entry in map.entries) {
  print('${entry.key} = ${entry.value}');
}

5. Search with Break

for (var item in items) {
  if (item.id == target) {
    found = item;
    break;
  }
}

6. Skip Invalid Items

for (var item in items) {
  if (!item.isValid) continue;
  process(item);
}

7. Retry Until Success

var attempts = 0;
var success = false;
while (!success && attempts < 3) {
  success = tryOperation();
  attempts++;
}

8. Validate Input

String? input;
do {
  input = readLine();
} while (input == null || input.isEmpty);

9. Nested Loop with Label

search:
for (var row in matrix) {
  for (var cell in row) {
    if (cell == target) break search;
  }
}

10. Functional Alternative

var total = items.fold<int>(0, (sum, item) => sum + item.price);

Visual

Loop Constructs

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  for:                                                        โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚  init โ†’ check โ†’ body โ†’ update โ†’ check โ†’ body โ†’ ...     โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚  Runs 0 or more times. Index available.                      โ”‚
โ”‚                                                              โ”‚
โ”‚  for-in:                                                     โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚  element 1 โ†’ body โ†’ element 2 โ†’ body โ†’ ...             โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚  Runs once per element. No index.                            โ”‚
โ”‚                                                              โ”‚
โ”‚  while:                                                      โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚  check โ†’ body โ†’ check โ†’ body โ†’ ...                     โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚  Runs 0 or more times.                                       โ”‚
โ”‚                                                              โ”‚
โ”‚  do-while:                                                   โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚  body โ†’ check โ†’ body โ†’ check โ†’ ...                     โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚  Runs 1 or more times.                                       โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

break and continue

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  for (var i = 0; i < 10; i++) {                              โ”‚
โ”‚    if (i == 5) break;       โ†’ exits loop at i = 5            โ”‚
โ”‚    if (i % 2 == 0) continue; โ†’ skips even numbers            โ”‚
โ”‚    print(i);                                                 โ”‚
โ”‚  }                                                           โ”‚
โ”‚                                                              โ”‚
โ”‚  Output: 1, 3                                                 โ”‚
โ”‚  (0 skipped by continue, 1 printed, 2 skipped, 3 printed,   โ”‚
โ”‚   4 skipped, 5 breaks)                                       โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Labeled Break

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  outer:                                                      โ”‚
โ”‚  for (var i = 0; i < 3; i++) {                               โ”‚
โ”‚    for (var j = 0; j < 3; j++) {                             โ”‚
โ”‚      if (i == 1 && j == 1) break outer;                      โ”‚
โ”‚      print('$i $j');                                         โ”‚
โ”‚    }                                                         โ”‚
โ”‚  }                                                           โ”‚
โ”‚                                                              โ”‚
โ”‚  Output:                                                     โ”‚
โ”‚  0 0                                                         โ”‚
โ”‚  0 1                                                         โ”‚
โ”‚  0 2                                                         โ”‚
โ”‚  1 0                                                         โ”‚
โ”‚  (break outer exits both loops)                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

for vs for-in

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  CLASSIC for:                    for-in:                     โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚ for (var i = 0;            โ”‚  โ”‚ for (var name          โ”‚  โ”‚
โ”‚  โ”‚      i < names.length;     โ”‚  โ”‚      in names) {       โ”‚  โ”‚
โ”‚  โ”‚      i++) {                โ”‚  โ”‚   print(name);         โ”‚  โ”‚
โ”‚  โ”‚   print('$i: ${names[i]}');โ”‚  โ”‚ }                      โ”‚  โ”‚
โ”‚  โ”‚ }                          โ”‚  โ”‚                        โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚  Index available                 No index                    โ”‚
โ”‚  Bounds check needed             No bounds check             โ”‚
โ”‚  Use when index matters          Use for plain iteration     โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Summary

ItemValue
forClassic loop with initializer, condition, update
for-inIterates over an Iterable
whileChecks condition before each iteration
do-whileChecks condition after each iteration
breakExit the loop
continueSkip to next iteration
Labelouter: before a loop, used with break outer
forEachMethod on iterables; no break or continue
Functional alternativesmap, where, reduce, fold
Concurrent modificationThrows ConcurrentModificationError

Key takeaways:

  • for-in is the idiomatic way to iterate over collections. It works with any Iterable, requires no bounds checking, and eliminates off-by-one errors. Use it unless the index is needed.
  • The classic for is for counting and index-based iteration. The initializer, condition, and update give precise control, and the index is available inside the body.
  • while checks before the body; do-while checks after. Use while when the body may run zero times, and do-while when it must run at least once.
  • break exits, continue skips. Both apply to the innermost loop unless a label is used. Labels allow break and continue to target an outer loop from within a nested one.
  • forEach cannot be broken out of. It applies a function to each element but has no break or continue. For iteration that needs control flow, use for-in.
  • Modifying a collection during iteration throws. Adding or removing elements while iterating with for-in or forEach produces a ConcurrentModificationError. Iterate over a copy or collect the changes and apply them after.
  • Functional methods express transformation more directly. map, where, reduce, and fold are often clearer than explicit loops when the goal is to transform or aggregate a collection.

Remember: Dart provides four loop constructs because there are four distinct iteration needs. for-in is the default for collections; the classic for is for counting and when the index matters; while is for condition-driven repetition; do-while guarantees at least one execution. The control statements break and continue handle early exit and skipping, and labels extend them to nested loops. The forEach method is a terminal operation that cannot be controlled with break or continue, and modifying a collection during iteration throws. For transformations and aggregations, the functional methods map, where, reduce, and fold are often more expressive than a loop. Choosing the right construct for the situation makes iteration readable and correct.



Stop using slow, ad-bloated tool sites! ๐Ÿคฎ

๐Ÿ”Ž Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
โœ… Finance (Mortgage, Interest, Inflation)
โœ… Tech (Base64, JSON, Dev Suite, IP)
โœ… Health (BMI, BMR, TDEE)
โœ… Productivity (Timer, Workspace, QR)

โšก๏ธ Fast & Private
๐Ÿ”’ No data leaves your device
๐Ÿ’Ž 100% Free

๐Ÿ”— Use it now: https://tools.kandz.me
๐Ÿ”– Bookmark itโ€”youโ€™ll need it later!