4 Control Flow Statements
Control flow statements allow you to control the execution path of your program based on conditions or to repeat blocks of code. Coming from Python, you’ll find many familiar concepts in Dart, though with some syntax differences. Let’s explore each type of control flow statement in Dart.
4.1 Conditional Statements
4.1.1 If-Else Statements
The basic if-else statement in Dart is similar to other languages:
void main() {
var temperature = 25;
if (temperature > 30) {
'It\'s hot outside!');
print(} else if (temperature > 20) {
'It\'s a nice day!');
print(} else {
'It\'s a bit cold!');
print(}
}
Notice that unlike Python:
- Dart uses curly braces
{}
to define code blocks - Conditions must be enclosed in parentheses
()
- No colon
:
is needed after the condition - Indentation is for readability but not syntactically significant
4.1.2 Conditional Expressions
Dart offers two conditional expressions for concise code:
4.1.2.1 Ternary Operator
Similar to Python’s ternary operator:
var result = condition ? valueIfTrue : valueIfFalse;
// Example
var age = 20;
var status = age >= 18 ? 'Adult' : 'Minor';
// Output: Adult print(status);
4.1.2.2 Null-Aware Operators
Dart has special operators for handling null values:
// ?? (if-null operator): Returns the expression on the left if it's not null,
// otherwise returns the expression on the right
var name = userName ?? 'Guest';
// ??= (null-aware assignment): Assigns a value only if the variable is null
??= 'Guest';
userName
// ?. (null-aware access): Accesses a property or calls a method only if the object is not null
var length = userName?.length; // Returns null if userName is null
4.1.3 Switch-Case Statements
Dart’s switch statement works with integers, strings, and compile-time constants:
void main() {
var grade = 'B';
switch (grade) {
case 'A':
'Excellent!');
print(break;
case 'B':
'Good job!');
print(break;
case 'C':
'Needs improvement');
print(break;
default:
'Invalid grade');
print(}
}
Important points:
- Each case must end with a
break
,continue
,return
, orthrow
- If you want to fall through to the next case, use
continue
with a label - The
default
case handles values that don’t match any case
Dart also supports case statements with multiple conditions using the when
clause (in Dart 3.0+):
void main() {
var score = 85;
switch (score) {
case var s when s >= 90:
'A grade');
print(break;
case var s when s >= 80:
'B grade');
print(break;
case var s when s >= 70:
'C grade');
print(break;
default:
'Failed');
print(}
}
4.2 Loops
4.2.1 For Loops
Dart supports several forms of for loops:
4.2.1.1 Standard For Loop
void main() {
for (var i = 0; i < 5; i++) {
'Count: $i');
print(}
}
4.2.1.2 For-In Loop (similar to Python’s for loop)
void main() {
var fruits = ['apple', 'banana', 'orange'];
for (var fruit in fruits) {
'I like $fruit');
print(}
}
4.2.1.3 For-Each Method
void main() {
var numbers = [1, 2, 3, 4, 5];
.forEach((number) {
numbers'Number: $number');
print(});
// Using arrow function
.forEach((number) => print('Number: $number'));
numbers}
4.2.2 While and Do-While Loops
4.2.2.1 While Loop
Executes a block of code as long as a condition is true:
void main() {
var counter = 0;
while (counter < 5) {
'Counter: $counter');
print(++;
counter}
}
4.2.2.2 Do-While Loop
Similar to while loop, but guarantees the block is executed at least once:
void main() {
var counter = 0;
do {
'Counter: $counter');
print(++;
counter} while (counter < 5);
}
4.3 Control Flow Modifiers
4.3.1 Break and Continue
break
: Exits the innermost loop or switch statementcontinue
: Skips to the next iteration of the loop
void main() {
for (var i = 0; i < 10; i++) {
if (i == 5) {
continue; // Skip printing 5
}
if (i == 8) {
break; // Exit the loop when i is 8
}
'Number: $i');
print(}
}
4.3.2 Assert
The assert
statement is used during development to verify conditions:
void main() {
var age = -5;
// This will throw an exception if the condition is false (in debug mode)
assert(age >= 0, 'Age cannot be negative');
'Age: $age');
print(}
Assert statements are only enabled in development mode and are ignored in production.
4.4 Exception Handling
Dart uses try-catch-finally blocks for exception handling:
void main() {
try {
var result = 10 ~/ 0; // Integer division by zero
'Result: $result'); // This line won't execute
print(} on IntegerDivisionByZeroException {
'Cannot divide by zero!');
print(} catch (e) {
'Error: $e');
print(} finally {
'This always executes');
print(}
}
Key points:
try
: Contains code that might cause an exceptionon
: Catches specific types of exceptionscatch
: Catches any exceptionfinally
: Contains code that always executes, whether an exception occurred or not
You can also throw exceptions:
void checkAge(int age) {
if (age < 0) {
throw ArgumentError('Age cannot be negative');
}
}
void main() {
try {
-5);
checkAge(} catch (e) {
'Error: $e');
print(}
}
4.5 Control Flow in Flutter Context
Let’s see how control flow statements are used in a Flutter application:
class WeatherApp extends StatefulWidget {
@override
=> _WeatherAppState();
_WeatherAppState createState() }
class _WeatherAppState extends State<WeatherApp> {
String _weatherCondition = 'Sunny';
int _temperature = 28;
@override
{
Widget build(BuildContext context) return Scaffold(
: AppBar(title: Text('Weather App')),
appBar: Center(
body: Column(
child: MainAxisAlignment.center,
mainAxisAlignment: [
children// Using if-else to determine the icon
Icon(== 'Sunny' ? Icons.wb_sunny :
_weatherCondition == 'Cloudy' ? Icons.cloud :
_weatherCondition .question_mark,
Icons: 80,
size: Colors.orange,
color,
)
// Using string interpolation with conditional logic
Text('It\'s $_temperature°C and $_weatherCondition',
: TextStyle(fontSize: 24),
style,
)
// Using a loop to generate multiple widgets
Container(: EdgeInsets.only(top: 20),
margin: 100,
height: ListView.builder(
child: Axis.horizontal,
scrollDirection: 5,
itemCount: (context, index) {
itemBuilderreturn Card(
: EdgeInsets.all(8),
margin: Container(
child: 80,
width: Alignment.center,
alignment: Text('Day ${index + 1}'),
child,
)
);},
,
),
),
],
),
): FloatingActionButton(
floatingActionButton: () {
onPressed{
setState(() // Using switch to update weather
switch (_weatherCondition) {
case 'Sunny':
= 'Cloudy';
_weatherCondition -= 5;
_temperature break;
case 'Cloudy':
= 'Rainy';
_weatherCondition -= 3;
_temperature break;
default:
= 'Sunny';
_weatherCondition = 28;
_temperature }
});
},
: Icon(Icons.refresh),
child,
)
);}
}
In this Flutter example, we’ve used:
- Conditional (ternary) expressions to determine which icon to show
- String interpolation with conditionals
- A
ListView.builder
that uses a loop internally to create multiple widgets - A switch statement inside the button’s onPressed callback
4.6 Comparing with Python
Let’s compare Dart’s control flow with Python:
4.6.1 If-Else
# Python
= 25
temperature
if temperature > 30:
print("It's hot outside!")
elif temperature > 20:
print("It's a nice day!")
else:
print("It's a bit cold!")
// Dart
var temperature = 25;
if (temperature > 30) {
'It\'s hot outside!');
print(} else if (temperature > 20) {
'It\'s a nice day!');
print(} else {
'It\'s a bit cold!');
print(}
4.6.2 Loops
# Python for loop
= ['apple', 'banana', 'orange']
fruits for fruit in fruits:
print(f"I like {fruit}")
# Python while loop
= 0
counter while counter < 5:
print(f"Counter: {counter}")
+= 1 counter
// Dart for-in loop
var fruits = ['apple', 'banana', 'orange'];
for (var fruit in fruits) {
'I like $fruit');
print(}
// Dart while loop
var counter = 0;
while (counter < 5) {
'Counter: $counter');
print(++;
counter}
4.6.3 Exception Handling
# Python
try:
= 10 // 0 # Integer division by zero
result print(f"Result: {result}")
except ZeroDivisionError:
print("Cannot divide by zero!")
except Exception as e:
print(f"Error: {e}")
finally:
print("This always executes")
// Dart
try {
var result = 10 ~/ 0; // Integer division by zero
'Result: $result');
print(} on IntegerDivisionByZeroException {
'Cannot divide by zero!');
print(} catch (e) {
'Error: $e');
print(} finally {
'This always executes');
print(}
4.7 Practical Exercise
Let’s create a simple Dart program that demonstrates various control flow statements:
void main() {
// List of students with their scores
var students = [
{'name': 'Alice', 'score': 95},
{'name': 'Bob', 'score': 85},
{'name': 'Charlie', 'score': 72},
{'name': 'David', 'score': 63},
{'name': 'Eve', 'score': 88},
];
'Student Grades:');
print('---------------');
print(
// Using a for-in loop to iterate through students
for (var student in students) {
var name = student['name'];
var score = student['score'] as int;
String grade;
// Using if-else to determine the grade
if (score >= 90) {
= 'A';
grade } else if (score >= 80) {
= 'B';
grade } else if (score >= 70) {
= 'C';
grade } else if (score >= 60) {
= 'D';
grade } else {
= 'F';
grade }
// Using string interpolation
'$name: $score - Grade: $grade');
print(}
'\nStatistics:');
print('---------------');
print(
// Using a forEach with an arrow function
var total = 0;
.forEach((student) => total += student['score'] as int);
students
// Using null-aware operator
var average = students.isEmpty ? 0 : total / students.length;
'Average score: ${average.toStringAsFixed(1)}');
print(
// Using while loop to find highest scorer
var i = 0;
var highestScore = 0;
var highestScorer = '';
while (i < students.length) {
var score = students[i]['score'] as int;
if (score > highestScore) {
= score;
highestScore = students[i]['name'] as String;
highestScorer }
++;
i}
'Highest score: $highestScore by $highestScorer');
print(
// Using try-catch for error handling
try {
var result = total ~/ (students.length - students.length); // Division by zero
'This won\'t print: $result');
print(} on IntegerDivisionByZeroException {
'Cannot calculate average of an empty list');
print(} catch (e) {
'An error occurred: $e');
print(}
}
This program demonstrates:
- For-in loops
- If-else statements
- String interpolation
- forEach with arrow functions
- Null-aware operators
- While loops
- Try-catch exception handling