[Dart Language Tour] Control flow statements, Assert, Exception
Control flow statements, Assert, Exception
Control flow statements
You can control the flow of your Dart code using any of the following:
-
if
andelse
-
for
loops -
while
anddo-while
loops -
break
andcontinue
-
switch
andcase
-
assert
You can also affect the control flow using try-catch
and throw
, as explained in Exceptions - https://dart.dev/guides/language/language-tour#exceptions.
If and else
Dart supports if
statements with optional else
statements, as the next sample shows. Also see conditional expressions - https://dart.dev/guides/language/language-tour#conditional-expressions.
1 | if (isRaining()) { |
Unlike JavaScript, conditions must use boolean
values, nothing else. See Booleans
- https://dart.dev/guides/language/language-tour#booleans for more information.
For loops
You can iterate with the standard for loop. For example:
1 | var message = StringBuffer('Dart is fun'); |
Closures inside of Dart’s for loops capture the value of the index, avoiding a common pitfall found in JavaScript. For example, consider:
1 | var callbacks = []; |
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, you can use the forEach()
- https://api.dart.dev/stable/dart-core/Iterable/forEach.html method. Using forEach()
is a good option if you don’t need to know the current iteration counter:
1 | candidates.forEach((candidate) => candidate.interview()); |
Iterable classes such as List
and Set
also support the for-in
form of iteration - https://dart.dev/guides/libraries/library-tour#iteration:
1 | var collection = [1, 2, 3]; |
While and do-while
A while
loop evaluates the condition before the loop:
1 | while (!isDone()) { |
A do-while
loop evaluates the condition after the loop:
1 | do { |
Break and continue
Use break
to stop looping:
1 | while (true) { |
Use continue
to skip to the next loop iteration:
1 | for (int i = 0; i < candidates.length; i++) { |
You might write that example differently if you’re using an Iterable such as a list or set:
1 | candidates |
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 - https://dart.dev/guides/language/language-tour#enumerated-typeswork 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:
1 | var command = 'OPEN'; |
The following example omits the break
statement in a case clause, thus generating an error:
1 | var command = 'OPEN'; |
However, Dart does support empty case clauses, allowing a form of fall-through:
1 | var command = 'CLOSED'; |
If you really want fall-through, you can use a continue
statement and a label:
1 | var command = 'CLOSED'; |
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:
1 | // Make sure the variable has a non-null value. |
To attach a message to an assertion, add a string as the second argument to assert (optionally with a trailing comma - https://dart.dev/guides/language/language-tour#trailing-comma):
1 | assert(urlString.startsWith('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
- https://dart.dev/guides/language/language-tour#trailing-comma) is thrown.
When exactly do assertions work? That depends on the tools and framework you’re using:
-
Flutter enables assertions in debug mode - https://flutter.dev/docs/testing/debugging#debug-mode-assertions.
-
Development-only tools such as dartdevc - https://dart.dev/tools/dartdevc typically enable assertions by default.
-
Some tools, such as dart - https://dart.dev/server/tools/dart-vm and dart2js - https://dart.dev/tools/dart2js, support assertions through a command-line flag: --enable-asserts.
In production code, assertions are ignored, and the arguments to assert aren’t evaluated.
Exceptions
Your Dart code can throw and catch exceptions. Exceptions are errors indicating that something unexpected happened. If the exception isn’t caught, the isolate
- https://dart.dev/guides/language/language-tour#isolates that raised the exception is suspended, and typically the isolate and its program are terminated.
In contrast to Java, all of Dart’s exceptions are unchecked exceptions. Methods do not declare which exceptions they might throw, and you are not required to catch any exceptions.
Dart provides Error
- https://api.dart.dev/stable/dart-core/Error-class.html and Exception
- https://api.dart.dev/stable/dart-core/Exception-class.html types, as well as numerous predefined subtypes. You can, of course, define your own exceptions. However, Dart programs can throw any non-null object—not just Exception and Error objects—as an exception.
Throw
Here’s an example of throwing, or raising, an exception:
1 | throw FormatException('Expected at least 1 section'); |
You can also throw
arbitrary objects:
1 | throw 'Out of llamas!'; |
Note: Production-quality code usually throws types that implement Error
- https://api.dart.dev/stable/dart-core/Error-class.html or Exception
- https://api.dart.dev/stable/dart-core/Exception-class.html.
Because throwing an exception is an expression, you can throw exceptions in =>
statements, as well as anywhere else that allows expressions:
1 | void distanceTo(Point other) => throw UnimplementedError(); |
Catch
Catching, or capturing, an exception stops the exception from propagating (unless you rethrow the exception). Catching an exception gives you a chance to handle it:
1 | try { |
To handle code that can throw more than one type of exception, you can specify multiple catch clauses. The first catch clause that matches the thrown object’s type handles the exception. If the catch clause does not specify a type, that clause can handle any type of thrown object:
1 | try { |
As the preceding code shows, you can use either on or catch or both. Use on when you need to specify the exception type. Use catch when your exception handler needs the exception object.
You can specify one or two parameters to catch()
. The first is the exception that was thrown, and the second is the stack trace (a StackTrace
- https://api.dart.dev/stable/dart-core/StackTrace-class.html object).
1 | try { |
To partially handle an exception, while allowing it to propagate, use the rethrow
keyword.
1 | void misbehave() { |
Finally
To ensure that some code runs whether or not an exception is thrown, use a finally
clause. If no catch clause matches the exception, the exception is propagated after the finally
clause runs:
1 | try { |
The finally
clause runs after any matching catch clauses:
1 | try { |
Learn more by reading the Exceptions
- https://dart.dev/guides/libraries/library-tour#exceptions section of the library tour.