Flutter: Null Safety

Jitesh Mohite
FlutterWorld
Published in
5 min readMar 23, 2021

As a developer, we always struggle to handle NullPointerException which causes a lot of time and money while developing software. It has been referred to as a billion-dollar mistake. (Wiki)

Flutter 2 supports null safety. You can now migrate your Flutter packages to use non-nullable types. Follow the below link to perform flutter migration for old projects.

https://dart.dev/null-safety/migration-guide

Note: To use it it’s necessary to have your all libs updated with a null safety feature, otherwise you can’t migrate your project to Flutter 2.

Dart distinguishes between nullable and non-nullable references as a part of its type system which helps in eliminating the risk of NullPointerException.

In Dart, all variables are non-nullable by default. We cannot assign a null value to a variable because it’ll throw a compilation error:

  final String country = null; // Cannot be null.
final String? country = null; // Can be null.

Null safety is a major new productivity feature that helps you avoid null exceptions, a class of bugs that are often hard to spot. As an added bonus, this feature also enables a range of performance improvements.

— — — — — — — — — — — — — — — — — — — — — — — — — —

Compile Time Error For Nullable Type.

Variables are non-nullable by default which means every variable should be assigned and cannot be null.

void main() {
String country;
print(country);
}
Error: The non-nullable local variable 'country' must be assigned before it can be used.

Values must be assigned at the time of declaration otherwise we have to mark it as nullable using ‘?’ Also, it is not possible to assign a value null to the variable, it will give an error “A country of type ‘Null’ can’t be assigned to a variable of type ‘String’.”

void main() {
String country = null;
}

The below code will work, as the variable country is not used before assigning a value.

void main() {
String country;
country = "Welcome To Flutter";
}

Below code gives us an error as we are using a variable before it got assigned value, and the error which thrown “The non-nullable local variable ‘value’ must be assigned before it can be used.”

void main() {
String country;
print(country);
country = "USA";
}

— — — — — — — — — — — — — — — — — — — — — — — — — —

Nullable types (Use Question Mark ‘?’)

To force variable nullable use ‘?’ like below, which tells the system that it can be null, and assigned letter. This will through null exception which results in a red screen on mobile.

void main() {
String? country;
print(country);
}
Output:
null

— — — — — — — — — — — — — — — — — — — — — — — — — —

Non Nullable Type — Exclamation mark (!)

Appending ! to any variable tells the compiler that the variable is not null, and can be used safely.

void main() {
String? country = "USA";
String myCountry = country!; // myCountry is non-nullable; would throw an error if country is null

— — — — — — — — — — — — — — — — — — — — — — — — — —

late variables

The keyword late can be used to mark variables that will be initialized later, i.e. not when they are declared but when they are accessed. This also means that we can have non-nullable instance fields that are initialized later: Accessing value before it is initialized will throw a runtime error.

void main() {
late String country; // non-nullable
// print(value) here would throw a runtime error
country = "USA";
}

— — — — — — — — — — — — — — — — — — — — — — — — — —

late final

Wow!!, isn’t these amazing, Final variable can be assigned a letter.

You can declare a late final without an initializer, which is the same as having just a late variable, but it can only be assigned once.

late final String country;
country = "USA";
print(country); // Working
country = "India";//Error: The late final local variable is already assigned.

If the late final is declared as static, then it will be evaluated at runtime.

class MyClass {
static late final country;
}

void main() {
MyClass.country = "USA";
MyClass.country = "USA";
print(MyClass.values.toString());
}
Output:
[VERBOSE-2:ui_dart_state.cc(186)] Unhandled Exception: LateInitializationError: Field 'values' has already been initialized.

This error will be thrown at runtime, not at the compile-time, so don't declare final late values again, this will cause a runtime error.

— — — — — — — — — — — — — — — — — — — — — — — — — —

Conditional operator(?)

The cascade operator helps us to verify whether the given object/variable is null or not if it's null then we can use another value, it’s more like if, else

class MyClass {
String? country;
}

void main() {
var myClass = MyClass();
print(myClass.country?? "Japan");
/// myClass.value is returning null, to avoid null exception we can /// pass placeholder value like above("Japan"), this must be
/// utilized whenever possible inside the code base.
}
Output: Japan

I have tried to put everything below the class file, respectively wrote test cases for it.

Example:

import 'package:flutter/material.dart';

class NullSafety {
int? nullCheckForCountry() {
String country = "USA";
// country = null; //compilation error
return country != null ? country.length : null;
}

int? safeCallForCountry() {
String? country;
return country?.length;
}

int? nullCheckForCity() {
String? city = "Kolkata";
city = null;
return city != null ? city.length : null;
}

int? safeCallForCity() {
String? city;
return city?.length;
}

String? safeCallChainForValue() {
Country? country = Country(City("Kolkata", "003"));
return country.city?.code;
}

List<String?> safeCallUsingList() {
List<String?> cities = ["Kolkata", null, "Mumbai"];
List<String?> name = [];
for (int i = 0; i < cities.length; i++) {
String? city = cities[i];
name.add(city);
}
return name;
}

String getDefaultValueIfObjectNull() {
Country? country = Country(City("New Delhi", null));
return country.city?.code ?? "Not available";
}

int? notNullAssertionForException() {
String? country;
return country!.length;
}
}

class Country {
City? city;

Country(City? city) {
this.city = city;
}
}

class City {
String? name;
String? code;

City(String? name, String? code) {
this.name = name;
this.code = code;
}
}

Class File: https://github.com/jitsm555/Null-Safety-Flutter/blob/master/lib/main.dart

Test File: https://github.com/jitsm555/Null-Safety-Flutter/blob/master/test/null_safety_test.dart

--

--

Jitesh Mohite
FlutterWorld

I am technology enthusiastic, want to learn things quickly and dive deep inside it. I always believe in developing logical things which makes impact on end user