Contents

Control flow statements

You can control the flow of your Dart code using any of the following:

  • if and else
  • for loops
  • while and do-while loops
  • break and continue
  • switch and case
  • assert

You can also affect the control flow using try-catch and throw, as explained in Exceptions.

If and else

Dart supports if statements with optional else statements, as the next sample shows. Also see conditional expressions.

if (isRaining()) {
  you.bringRainCoat();
} else if (isSnowing()) {
  you.wearJacket();
} else {
  car.putTopDown();
}

The statement conditions must be expressions that evaluate to boolean values, nothing else. See Booleans for more information.

For loops

You can iterate with the standard for loop. For example:

var message = StringBuffer('Dart is fun');
for (var i = 0; i < 5; i++) {
  message.write('!');
}

Closures inside of Dart’s for loops capture the value of the index, avoiding a common pitfall found in JavaScript. For example, consider:

var callbacks = [];
for (var i = 0; i < 2; i++) {
  callbacks.add(() => print(i));
}

for (final c in callbacks) {
  c();
}

The output is 0 and then 1, as expected. In contrast, the example would print 2 and then 2 in JavaScript.

If the object that you are iterating over is an Iterable (such as List or Set) and if you don’t need to know the current iteration counter, you can use the for-in form of iteration:

for (final candidate in candidates) {
  candidate.interview();
}

Iterable classes also have a forEach() method as another option:

var collection = [1, 2, 3];
collection.forEach(print); // 1 2 3

While and do-while

A while loop evaluates the condition before the loop:

while (!isDone()) {
  doSomething();
}

A do-while loop evaluates the condition after the loop:

do {
  printLine();
} while (!atEndOfPage());

Break and continue

Use break to stop looping:

while (true) {
  if (shutDownRequested()) break;
  processIncomingRequests();
}

Use continue to skip to the next loop iteration:

for (int i = 0; i < candidates.length; i++) {
  var candidate = candidates[i];
  if (candidate.yearsExperience < 5) {
    continue;
  }
  candidate.interview();
}

You might write that example differently if you’re using an Iterable such as a list or set:

candidates
    .where((c) => c.yearsExperience >= 5)
    .forEach((c) => c.interview());

Switch and case

Switch statements in Dart compare integer, string, or compile-time constants using ==. The compared objects must all be instances of the same class (and not of any of its subtypes), and the class must not override ==. Enumerated types work well in switch statements.

Each non-empty case clause ends with a break statement, as a rule. Other valid ways to end a non-empty case clause are a continue, throw, or return statement.

Use a default clause to execute code when no case clause matches:

var command = 'OPEN';
switch (command) {
  case 'CLOSED':
    executeClosed();
    break;
  case 'PENDING':
    executePending();
    break;
  case 'APPROVED':
    executeApproved();
    break;
  case 'DENIED':
    executeDenied();
    break;
  case 'OPEN':
    executeOpen();
    break;
  default:
    executeUnknown();
}

The following example omits the break statement in a case clause, thus generating an error:

var command = 'OPEN';
switch (command) {
  case 'OPEN':
    executeOpen();
    // ERROR: Missing break

  case 'CLOSED':
    executeClosed();
    break;
}

However, Dart does support empty case clauses, allowing a form of fall-through:

var command = 'CLOSED';
switch (command) {
  case 'CLOSED': // Empty case falls through.
  case 'NOW_CLOSED':
    // Runs for both CLOSED and NOW_CLOSED.
    executeNowClosed();
    break;
}

If you really want fall-through, you can use a continue statement and a label:

var command = 'CLOSED';
switch (command) {
  case 'CLOSED':
    executeClosed();
    continue nowClosed;
  // Continues executing at the nowClosed label.

  nowClosed:
  case 'NOW_CLOSED':
    // Runs for both CLOSED and NOW_CLOSED.
    executeNowClosed();
    break;
}

A case clause can have local variables, which are visible only inside the scope of that clause.

Assert

During development, use an assert statement—assert(condition, optionalMessage);—to disrupt normal execution if a boolean condition is false. You can find examples of assert statements throughout this tour. Here are some more:

// Make sure the variable has a non-null value.
assert(text != null);

// Make sure the value is less than 100.
assert(number < 100);

// Make sure this is an https URL.
assert(urlString.startsWith('https'));

To attach a message to an assertion, add a string as the second argument to assert (optionally with a trailing comma):

assert(urlString.startsWith('https'),
    'URL ($urlString) should start with "https".');

The first argument to assert can be any expression that resolves to a boolean value. If the expression’s value is true, the assertion succeeds and execution continues. If it’s false, the assertion fails and an exception (an AssertionError) is thrown.

When exactly do assertions work? That depends on the tools and framework you’re using:

  • Flutter enables assertions in debug mode.
  • Development-only tools such as [webdev serve][] typically enable assertions by default.
  • Some tools, such as dart run and [dart compile js][] support assertions through a command-line flag: --enable-asserts.

In production code, assertions are ignored, and the arguments to assert aren’t evaluated.