On this page22 sections
- Prerequisites
- Connection With Previous Lectures
- Learning Objectives
- 1. A Value Dart Cannot Trust
- 2. What Is the Null Assertion Operator?
- 3. Using !
- 4. Copying into a Non-Nullable Variable
- 5. Properties and Methods Through !
- 6. When the Promise Is Broken
- 7. ! Moves the Error to Run Time
- 8. When ! Is Unnecessary
- 9. !, ??, or ?.?
- 10. A Real-World Example
- Code Examples
- Common Beginner Mistakes
- Best Practices
- Mini Challenge
- Practice Questions
- Practice Answers
- Quick Revision
- Key Takeaways
- What's Next?
Lecture 15 — Null Assertion Operator !
| Category | 3 — Null Safety |
| Lecture | 015 of 140 |
| Estimated video length | 8 min |
| Target | Dart 3.12.2 |
| Level | Beginner |
Sometimes you know a nullable value is not
null, but Dart can't see it. The null assertion operator!lets you say "trust me, there is a value" — and crashes the program if you are wrong.
Contents
Prerequisites · Connection · Objectives · Lesson · Code Examples · Common Mistakes · Best Practices · Mini Challenge · Practice Questions · Answers · Takeaways
Every error message in this lecture is real. Each one was produced by running the code shown on Dart 3.12.2, so you will recognize it when you meet it yourself.
Prerequisites
Students should already understand, from Lectures 004–014:
- declaring variables with a type and with
var, andlate(Lecture 006) - converting text to numbers with
int.tryParseanddouble.tryParse, which returnnullfor invalid text (Lecture 010) - the difference between a compile-time error and a run-time crash, and
asas a promise (Lecture 011) null, nullable types such asint?, and why Dart refuses to use them directly (Lectures 012–013)- the null-aware operators
??,??=, and?.(Lecture 014)
Connection With Previous Lectures
In Lecture 014 we handled a possible null by giving a default with ?? or by skipping the
work with ?.. Both assume the value really might be missing. But look at this:
void main() {
int? quantity = int.tryParse('3');
// int total = quantity * 500; // ✗ quantity is int?
}The text is '3' — written by us, not typed by a user. It can never fail to parse. A
default like ?? 0 would be a lie, because 0 can never happen. We need a way to tell Dart:
this value is definitely there.
Learning Objectives
By the end of this lecture you will be able to:
- Explain what the null assertion operator
!does - Use
!to turn a nullable value into a non-nullable one - Call properties and methods through
! - Recognize the run-time error
Null check operator used on a null value - Explain why
!moves a mistake from compile time to run time - Recognize when
!is unnecessary - Choose between
!,??, and?. - Use
!only when you can prove a value is notnull
1. A Value Dart Cannot Trust
int.tryParse returns an int?: a number, or null if the text is not a number. Dart
checks the type, not the text, so it treats every result as possibly missing — even
'40':
void main() {
int? score = int.tryParse('40');
int total = score + 5;
print(total);
}Error: Operator '+' cannot be called on 'int?' because it is potentially null.
int total = score + 5;
^
Error: A value of type 'num' can't be assigned to a variable of type 'int'.
int total = score + 5;
^The first message is the real problem; the second is a side effect of it. Your editor's hint even suggests the fix: "Try adding a null check to the target ('!')."
2. What Is the Null Assertion Operator?
The null assertion operator is an exclamation mark written straight after a value:
score!. It means: "this value is not null — treat it as non-nullable."
Analogy — think of a signed guarantee. A shopkeeper won't hand over goods for a cheque he can't verify — until you sign "I guarantee this cheque is good". He accepts it at once. But if the cheque bounces, the trouble comes later, and it is yours.
Dart accepts score! straight away. If score really holds null, the trouble comes when
the program runs.
3. Using !
Add ! to the nullable value, and the error from Step 1 disappears:
void main() {
int? score = int.tryParse('40');
int total = score! + 5;
print(total);
}45score has type int?, but score! has type int — so + is allowed and the result fits
in an int variable. Also called the null check or bang operator, ! changes only
the type Dart sees; the value 40 is untouched.
4. Copying into a Non-Nullable Variable
A nullable value can't go straight into a non-nullable variable (Lecture 013). With !, it
can:
void main() {
int? parsed = int.tryParse('25');
int age = parsed!;
print('Age: $age');
}Age: 25From here on, age is an ordinary int, and you never need ! for it again.
5. Properties and Methods Through !
! also works in front of a dot. Write it between the value and the property or method:
void main() {
double? price = double.tryParse('1299.5');
print(price!.toStringAsFixed(2));
print(price.round());
}1299.50
1300Notice line two: price.round() needs no !. Once a local variable has passed a !
check, Dart remembers that it is not null for the lines that follow.
6. When the Promise Is Broken
Now give ! a value that really is null:
void main() {
int? score = int.tryParse('forty');
print('Calculating...');
int total = score! + 5;
print(total);
}Calculating...
Unhandled exception:
Null check operator used on a null valueThis compiled without a single complaint. The program started, printed Calculating...,
and crashed only when it reached score!. The message says exactly what happened: a null
check (!) met a null value.
Dart also prints a few lines showing where the crash happened. We will learn to read them when we cover errors and exceptions, starting in Lecture 083.
7. ! Moves the Error to Run Time
This is the heart of the lecture. Remember compile time vs run time from Lecture 011:
Without ! | With ! | |
|---|---|---|
| Value is a number | compile-time error | works |
Value is null | compile-time error | run-time crash |
Without !, Dart stops you before anything runs — safe. With !, you switch that check off
for one value, just as as does in Lecture 011 and late does in Lecture 006. ! is
honest only when you can say why the value cannot be null.
8. When ! Is Unnecessary
If Dart can already see that a value is not null, ! does nothing. Here the value is
written right on the same line:
void main() {
String? name = 'Ali';
print(name!.length);
}3It runs, but your editor and dart analyze warn you:
warning - The '!' will have no effect because the receiver can't be null. Try removing the '!' operator.The same happens with a non-nullable variable such as String name = 'Ali'; — name! is
pointless, because name can never be null. Use ! only for values Dart can't see:
results of tryParse, and later, data from users, files, maps, and functions.
9. !, ??, or ?.?
You now have three ways to handle a nullable value. They answer different questions:
void main() {
int? marks = int.tryParse('abc');
print(marks ?? 0);
print(marks?.isEven);
// print(marks!); // ✗ would crash here
}0
null| Operator | Use it when… | If the value is null… |
|---|---|---|
value ?? fallback | a missing value is normal and has a sensible default | uses the fallback |
value?.member | you want to skip the work when the value is missing | gives null |
value! | the value cannot be missing — you can prove it | crashes |
For anything a user types, null is a normal outcome — use ?? or ?.. Keep ! for values
that are guaranteed.
The ! written before a bool, as in !isStudent, is a different operator — "not".
It belongs to Lecture 019, Logical Operators.
10. A Real-World Example
A shop's checkout reads two numbers as text. The unit price comes from the shop's own
price tag, '450' — it is always valid. The quantity is typed by the customer, Zayan, and
might be anything:
void main() {
String priceTag = '450';
String typedQuantity = 'two';
int price = int.tryParse(priceTag)!;
int quantity = int.tryParse(typedQuantity) ?? 1;
int total = price * quantity;
print('Price: $price');
print('Quantity: $quantity');
print('Total: $total');
}Price: 450
Quantity: 1
Total: 450The price tag is ours, so ! is a promise we can keep. Zayan's input is not ours, so it gets
a safe default with ??. Had we written ! on the quantity, the checkout would have crashed
on 'two'.
Code Examples
Example 1 — Turning int? into int
void main() {
int? parsed = int.tryParse('12');
int number = parsed!;
print(number);
}12Example 2 — Arithmetic Through !
void main() {
int? a = int.tryParse('8');
int? b = int.tryParse('7');
print(a! * b!);
}56Example 3 — Directly on a Result
void main() {
int doubled = int.tryParse('21')! * 2;
print(doubled);
}42How it works
int.tryParse('21')gives anint?.!is applied to that result at once, giving anint, so* 2is allowed.
Example 4 — A Method Through !
void main() {
double? weight = double.tryParse('72.456');
print(weight!.toStringAsFixed(1));
}72.5Example 5 — Dart Remembers After !
void main() {
int? steps = int.tryParse('9000');
print(steps!.isEven);
print(steps + 1000);
}true
10000How it works
steps!passes the null check, so Dart now knowsstepsis notnull.- On the next line,
steps + 1000needs no!.
Example 6 — ! Next to ??
void main() {
int? sure = int.tryParse('5');
int? unsure = int.tryParse('five');
print(sure!);
print(unsure ?? 0);
}5
0Example 7 — Student Marks
void main() {
int math = int.tryParse('85')!;
int science = int.tryParse('90')!;
int total = math + science;
print('Student: Sara');
print('Total: $total');
}Student: Sara
Total: 175How it works
- Both marks are fixed text written in the program, so
!is safe. - After
!, each mark is a plainint, and they add normally.
Example 8 — Shopping Total
void main() {
double price = double.tryParse('249.99')!;
int quantity = int.tryParse('3')!;
double total = price * quantity;
print('Total: ${total.toStringAsFixed(2)}');
}Total: 749.97Example 9 — Bank Balance
void main() {
double balance = double.tryParse('5000.0')!;
double? deposit = double.tryParse('');
balance = balance + (deposit ?? 0);
print('Owner: Ali');
print('Balance: $balance');
}Owner: Ali
Balance: 5000.0How it works
- The starting balance is fixed text, so
!is safe. - The deposit field was left empty —
double.tryParse('')givesnull— so??supplies0instead. A!here would crash.
Example 10 — Temperature Conversion
void main() {
double? celsius = double.tryParse('30');
double fahrenheit = celsius! * 9 / 5 + 32;
print('Celsius: $celsius');
print('Fahrenheit: $fahrenheit');
}Celsius: 30.0
Fahrenheit: 86.0How it works
double.tryParse('30')gives thedouble30.0, typed asdouble?.celsius!makes the arithmetic allowed; the result fits in adouble.
Common Beginner Mistakes
1. Using a nullable value without handling it
void main() {
int? score = int.tryParse('40');
// int total = score + 5; // ✗
}Error: Operator '+' cannot be called on 'int?' because it is potentially null.Decide first: is null possible? If not, write score!. If it is, use score ?? 0.
2. Using ! on a value that can be null
void main() {
int? age = int.tryParse('twenty');
// print(age! + 1); // ✗ compiles, then crashes
}Unhandled exception:
Null check operator used on a null value! does not fix a missing value — it only promises there isn't one. Use ?? for text that
might be invalid.
3. Thinking ! turns null into 0
void main() {
int? bonus = int.tryParse('');
// int points = bonus!; // ✗ crashes — it does not become 0
}Unhandled exception:
Null check operator used on a null valueFor "use 0 when missing", write bonus ?? 0.
4. Putting ! in the wrong place
void main() {
int? n = int.tryParse('5');
// print((n + 1)!); // ✗
}Error: Operator '+' cannot be called on 'int?' because it is potentially null.! belongs on the nullable value itself, before you use it: n! + 1.
5. Adding ! where nothing can be null
void main() {
String name = 'Ali';
// print(name!.length); // ⚠ runs, but warns
}warning - The '!' will have no effect because the receiver can't be null. Try removing the '!' operator.Remove the !. A ! should always mean "this could be null, but here it isn't".
Best Practices
- Use
!only when you can explain in one sentence why the value cannot benull. - Never use
!just to make a compile-time error go away. - For anything that comes from a user, prefer
??or?.to!. - Apply
!once, into a non-nullable variable (int age = parsed!;), instead of repeating it on every line. - Remove a
!when your editor says it has no effect. - If you find yourself writing many
!s, rethink the types — maybe the variable should not be nullable at all.
Mini Challenge
A gym records Sara's weight as text. Her starting weight '68.4' comes from the gym's own
scale, and her lost weight '2.9' comes from the same scale. Convert both and print her
new weight with one decimal place.
Your program should print exactly:
New weight: 65.5 kgTry it yourself before opening the solution.
Show solution
void main() {
double start = double.tryParse('68.4')!;
double lost = double.tryParse('2.9')!;
double current = start - lost;
print('New weight: ${current.toStringAsFixed(1)} kg');
}New weight: 65.5 kgHow it works
- Both values come from a trusted scale, so
!is a promise we can keep. - After
!, both are plaindoubles, so subtraction is allowed. toStringAsFixed(1)shows one decimal place.
Practice Questions
Work through these in order — they run from beginner to application to challenge. Every question gives you exact values, so you can compare your output with the answers.
Beginner
-
Declare
int? parsed = int.tryParse('15');. Copy it into anintvariable namedcountusing!, and printcount. -
Use
!to print the result ofint.tryParse('9')multiplied by9. -
Which of these lines crash when run? Answer first, then check by running each one separately.
print(int.tryParse('7')!); print(int.tryParse('seven')!); print(int.tryParse('7') ?? 0); print(int.tryParse('seven') ?? 0);
Application
-
Declare
double? price = double.tryParse('99.999');. Use!to print it with two decimal places. -
This program does not compile. Fix it by adding one character, so that it prints
30:void main() { int? width = int.tryParse('6'); int area = width * 5; print(area); } -
Ali's marks are fixed text:
'72'and'64'. Use!to convert both and printTotal: 136. -
This program compiles but crashes. Explain in one sentence why, then fix it without using
!so it printsPoints: 0:void main() { int? points = int.tryParse('none'); print('Points: ${points!}'); } -
Declare
int? year = int.tryParse('2026');. Use!once to print whether it is even, then printyear + 1on the next line without another!.
Challenge
- Zayan's account starts at the fixed text
'1200.0'. He types a withdrawal of'abc'. Convert the balance with!and the withdrawal with??(default0), and printBalance: 1200.0. Explain in one sentence why each operator was the right choice. - A thermometer sends the fixed reading
'21.5'in Celsius. Convert it with!, then printFahrenheit: 70.7.
Practice Answers
Question 1 — Solution
void main() {
int? parsed = int.tryParse('15');
int count = parsed!;
print(count);
}15Question 2 — Solution
void main() {
print(int.tryParse('9')! * 9);
}81Question 3 — Solution
Only the second line crashes: 'seven' is not a number, so tryParse gives null, and !
meets it.
void main() {
print(int.tryParse('7')!);
print(int.tryParse('7') ?? 0);
print(int.tryParse('seven') ?? 0);
}7
7
0Run alone, the second line prints:
Unhandled exception:
Null check operator used on a null valueQuestion 4 — Solution
void main() {
double? price = double.tryParse('99.999');
print(price!.toStringAsFixed(2));
}100.00Question 5 — Solution
Add ! after width:
void main() {
int? width = int.tryParse('6');
int area = width! * 5;
print(area);
}30Question 6 — Solution
void main() {
int first = int.tryParse('72')!;
int second = int.tryParse('64')!;
print('Total: ${first + second}');
}Total: 136Question 7 — Solution
It crashes because 'none' is not a number, so points is null — and ! promised it
wasn't. Use ?? instead:
void main() {
int? points = int.tryParse('none');
print('Points: ${points ?? 0}');
}Points: 0Question 8 — Solution
void main() {
int? year = int.tryParse('2026');
print(year!.isEven);
print(year + 1);
}true
2027After year! passes, Dart knows year is not null, so the second line needs no !.
Question 9 — Solution
void main() {
double balance = double.tryParse('1200.0')!;
double withdrawal = double.tryParse('abc') ?? 0;
balance = balance - withdrawal;
print('Balance: $balance');
}Balance: 1200.0The balance is fixed text that always parses, so ! is a safe promise; the withdrawal is
typed by a person and may be invalid, so it needs a default.
Question 10 — Solution
void main() {
double celsius = double.tryParse('21.5')!;
double fahrenheit = celsius * 9 / 5 + 32;
print('Fahrenheit: $fahrenheit');
}Fahrenheit: 70.7Quick Revision
- What does
!written after a value do? - What type is
score!whenscoreis anint?? - What is the exact error message when
!meetsnull? - Is that a compile-time error or a run-time error?
- Why doesn't Dart need
!onpriceafterprice!has run once? - What warning appears when you use
!on a value that can't benull? - Which operator should you choose for text a user types:
!or??? Why?
Key Takeaways
- The null assertion operator
!is written after a value and turnsT?intoT. - It changes only the type Dart sees — the value itself is untouched.
!works in calculations, assignments, and before a dot:price!.round().- If the value is
null, the program stops withNull check operator used on a null value. !replaces a safe compile-time error with a possible run-time crash.- After a local variable passes
!, Dart knows it is notnullon the following lines. !on a value that can't benullhas no effect, and Dart warns you.- Use
??or?.whennullis possible; use!only when you can prove it isn't.
What's Next?
Lecture 016 — Null Safety in Real Code. You now know every null-safety tool: nullable
types, ??, ??=, ?., and !. Next we bring them together in realistic programs — user
input, optional details, values that arrive late — and practice choosing the right tool for
each situation, so null safety becomes a habit instead of a puzzle.