The ? and ! Operators
Part of the Object Oriented Programming section of Coddy's Dart journey — lesson 25 of 110.
When working with nullable types, Dart provides two essential operators to access values safely. The null-aware access operator ?. and the null assertion operator ! give you control over how you handle potentially null values.
The ?. operator safely accesses properties or methods on a nullable value. If the value is null, the entire expression returns null instead of crashing:
String? name = 'Alice';
print(name?.length); // 5
name = null;
print(name?.length); // null (no crash!)The ! operator tells Dart "I'm certain this value is not null." It converts a nullable type to non-nullable, but throws an error if the value actually is null:
String? maybeName = 'Bob';
String definite = maybeName!; // OK - we assert it's not null
print(definite.length); // 3
String? empty = null;
// String crash = empty!; // Runtime error! Value was nullUse ?. when you want to gracefully handle null values. Use ! only when you're absolutely certain a value exists - perhaps after checking it with an if statement or when you know the logic guarantees a value. Overusing ! defeats the purpose of null safety and can lead to runtime crashes.
Challenge
EasyLet's build a product inventory system that demonstrates how to safely work with nullable values using the ?. and ! operators.
You'll create two files to organize your code:
product.dart: Define aProductclass that represents an item in inventory. Some products have complete information, while others are still being cataloged. Your class should have:- A non-nullable
String name- every product must have a name - A non-nullable
double price- every product must have a price - A nullable
String? description- some products don't have descriptions yet - A nullable
String? category- some products haven't been categorized - A constructor that takes
nameandpriceas required parameters - A method
getDescriptionLength()that returns the length of the description using?., ornullif there's no description - A method
getCategoryUppercase()that returns the category in uppercase using!- this method assumes the category has been set - A method
displayProduct()that prints the product information, showingNo descriptionwhen description is null andUncategorizedwhen category is null
- A non-nullable
main.dart: Import your product class and demonstrate both operators:- Create a product named
'Laptop'with price999.99, then set its description to'High-performance computing device'and category to'Electronics' - Create a product named
'Mystery Item'with price49.99(leave description and category as null) - For the Laptop: call
displayProduct(), printDescription length: [length]usinggetDescriptionLength(), and printCategory: [uppercase]usinggetCategoryUppercase() - For the Mystery Item: call
displayProduct()and printDescription length: [length]usinggetDescriptionLength()(this will shownull)
- Create a product named
The displayProduct() method should print in this format:
Product: [name] - $[price]
Description: [description or "No description"]
Category: [category or "Uncategorized"]Expected output:
Product: Laptop - $999.99
Description: High-performance computing device
Category: Electronics
Description length: 32
Category: ELECTRONICS
Product: Mystery Item - $49.99
Description: No description
Category: Uncategorized
Description length: nullCheat sheet
The null-aware access operator ?. safely accesses properties or methods on nullable values. If the value is null, it returns null instead of throwing an error:
String? name = 'Alice';
print(name?.length); // 5
name = null;
print(name?.length); // null (no crash!)The null assertion operator ! converts a nullable type to non-nullable. Use it only when you're certain the value is not null, as it will throw a runtime error if the value is actually null:
String? maybeName = 'Bob';
String definite = maybeName!; // OK - asserts it's not null
print(definite.length); // 3
String? empty = null;
// String crash = empty!; // Runtime error!Use ?. for graceful null handling and ! only when you're absolutely certain a value exists.
Try it yourself
import 'product.dart';
void main() {
// TODO: Create a product named 'Laptop' with price 999.99
// Then set its description to 'High-performance computing device'
// And set its category to 'Electronics'
// TODO: Create a product named 'Mystery Item' with price 49.99
// Leave description and category as null
// TODO: For the Laptop:
// - Call displayProduct()
// - Print "Description length: [length]" using getDescriptionLength()
// - Print "Category: [uppercase]" using getCategoryUppercase()
// TODO: For the Mystery Item:
// - Call displayProduct()
// - Print "Description length: [length]" using getDescriptionLength()
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesLibraries & ImportsIntroduction to OOPClasses vs ObjectsThe this KeywordMethodsInstance VariablesConstructor BasicsRecap - Simple Calculator4Null Safety
Intro to Null SafetyNullable vs Non-NullableThe ? and ! OperatorsLate Keyword & Null SafetyNull-Aware OperatorsNull Safety in ClassesRecap - User Profile System7Abstract Classes & Interfaces
Abstract ClassesAbstract MethodsInterfaces in DartImplicit InterfacesImplementing vs ExtendingMultiple InterfacesRecap - Shape Calculator10Collections & Generics
List, Set, Map OverviewType-Safe CollectionsGeneric ClassesGeneric MethodsGeneric ConstraintsIterable & IteratorRecap - Generic Storage13Advanced OOP Concepts
Composition vs InheritanceExtension MethodsCallable ClassesSealed Classes (Dart 3)Records (Dart 3)Patterns & Matching (3.0)Enums with Methods16Project: Library Management
Project OverviewBook and User Classes2Constructors in Dart
Default ConstructorNamed ConstructorsInitializer ListsConstant ConstructorsFactory ConstructorsRedirecting ConstructorsRecap - Shape Builder5Encapsulation
Public vs Private MembersThe _ Prefix ConventionLibrary-Level PrivacyGetters & Setters DepthInformation HidingRecap - Student Records8Mixins
Introduction to MixinsCreating MixinsUsing Multiple Mixinson Keyword in MixinsMixin vs InheritanceMixin vs InterfaceRecap - Animal System11Special Methods
toString() OverridehashCode & == OverrideComparable Interfacecall() MethodnoSuchMethod OverrideRecap - Custom Collection14Design Patterns Part 1
Intro to Design PatternsSingleton PatternFactory PatternObserver PatternStrategy Pattern3Class Properties
Instance vs Static MembersFinal & Const FieldsLate VariablesStatic Methods & FieldsGetters and SettersRecap - Bank Account Manager6Inheritance
Basic InheritanceThe super KeywordMethod OverridingThe @override AnnotationThe final Class KeywordConstructors & InheritanceRecap - Employee Hierarchy9Polymorphism
Polymorphism BasicsPolymorphism via InterfacesRuntime Type CheckingThe is & as OperatorsCovariant KeywordRecap - Payment Processor