← Flutter & Dart

Dart Fundamentals

What is null safety in Dart, and what are `?`, `!`, `??`, and `late` for?

Show answer — try answering out loud first

Null safety means that, by default, a variable can't be null unless you say so explicitly with ?. This moves an entire family of errors (the infamous NullPointerException) from runtime to compile time. ? marks a type as nullable, ! asserts that something isn't null, ?? provides a default value, and late promises to initialize later.

Before, any variable could be null, and the error only showed up at runtime. With null safety, String is never null; if you want to allow null, you write String?.

The key operators:

  • ? (nullable type): String? name can be text or null.
  • ?. (safe access): user?.name returns null if user is null, instead of blowing up.
  • ?? (default value): name ?? "guest" uses "guest" if name is null.
  • ??= (assign if null): name ??= "guest" assigns only if name was null.
  • ! (null assertion): name! promises the compiler "this isn't null, trust me." If you're wrong, it blows up at runtime.
  • late: promises that you'll initialize the variable before using it. Useful when you can't give it a value at declaration but know it will exist.
void main() {
  String? name; // can be null
  print(name); // null

  // ?. safe access
  print(name?.length); // null (doesn't blow up)

  // ?? default value
  print(name ?? "guest"); // "guest"

  // ??= assign only if null
  name ??= "Mike";
  print(name); // "Mike"

  // ! asserts it's not null (use with care)
  String? maybe = "hi";
  String safe = maybe!; // OK because it wasn't null
  print(safe.length); // 2

  // late: I promise to initialize before using
  late String greeting;
  greeting = "Hello";
  print(greeting); // "Hello"
}

Overusing the ! operator to "silence" the compiler. variable! doesn't check anything: if the variable is null at that moment, your app blows up just like before null safety. ! should only be used when you truly know the value exists; in most cases ?? or a check with if (variable != null) is better.

"Null safety makes variables non-nullable by default; if I want to allow null, I use ?, like in String?. That turns null errors into compile-time errors instead of production crashes. To work with nullables I have ?. for safe access, ?? to provide a default value, and ! to assert that something isn't null, though I avoid ! because it doesn't check anything and can blow up at runtime. I use late when I know I'll initialize the variable later, not at declaration."

Quick challenge

What does this code print?

String? text;
print(text?.length ?? -1);
See answer

It prints -1. text is null, so text?.length returns null (thanks to ?. it doesn't blow up). Then ?? -1 replaces that null with -1.