Masukkan Password
19 Null Safety in Dart & Flutter | Dart Tutorial #18
Video ini membahas salah satu konsep paling penting di Dart dan Flutter, yaitu Null Safety. Saya akan menjelaskannya dari dasar, menggunakan bahasa sederhana, sekaligus meluruskan beberapa bagian transcript yang kurang tepat.
1. Apa itu Null Safety?
Pertama, kita perlu memahami apa itu null.
null artinya:
tidak ada nilai / belum memiliki objek atau data.
Contoh sederhana:
String? name = null;
Artinya variabel name saat ini tidak memiliki nilai String.
Bayangkan ada sebuah kotak bernama name.
"Budi"→ kotaknya berisi sesuatu."Andi"→ kotaknya berisi sesuatu.null→ kotaknya kosong.
2. Masalah yang ingin diselesaikan Null Safety
Sebelum Null Safety, kita bisa mempunyai kode seperti:
String name = null;
Kemudian:
print(name.length);
Masalahnya adalah:
Bagaimana kalau
nameternyatanull?
Program mencoba mencari .length dari sesuatu yang tidak ada.
Hal seperti ini sering menyebabkan error yang dikenal sebagai null pointer exception / null reference error.
Contohnya secara konsep:
name → null
name.length
↑
"Ambil length dari sesuatu yang kosong"
Inilah salah satu masalah yang ingin dikurangi oleh Null Safety.
3. Dart menggunakan Sound Null Safety
Dart modern menggunakan sound null safety.
Konsep sederhananya:
Dart akan membantu memastikan bahwa variabel yang dinyatakan tidak boleh null memang tidak digunakan seolah-olah bisa null.
Contoh:
String name;
print(name);
Ini error.
Kenapa?
Karena:
String name;
berarti:
“
nameharus berisiString, bukannull.”
Tetapi kita belum memberikan nilai kepada name.
Jadi Dart berkata kira-kira:
“Kamu belum mengisi
name, tetapi sudah mencoba menggunakannya.”
4. Non-nullable variable
Ini adalah konsep yang sangat penting.
Ketika kita menulis:
String name = "Budi";
name adalah non-nullable.
Artinya:
name → boleh String
name → tidak boleh null
Jadi ini tidak diperbolehkan:
String name = null;
Karena String secara default adalah non-nullable.
Begitu juga:
int age = 20;
double price = 10.5;
bool isLogin = true;
Ketiganya secara default tidak boleh berisi null.
5. Nullable variable
Lalu bagaimana kalau kita memang membutuhkan variabel yang boleh null?
Gunakan tanda:
?
Contoh:
String? name;
Sekarang artinya berbeda.
String? name
↓
name boleh String
atau
name boleh null
Contoh:
String? name = null;
Valid.
Kemudian:
name = "Budi";
juga valid.
Jadi:
String? name;
name = null; // boleh
name = "Budi"; // boleh
6. Perbedaan String dan String?
Ini wajib benar-benar dipahami.
String
String name = "Budi";
Maksudnya:
name:
✅ "Budi"
✅ "Andi"
❌ null
String?
String? name = null;
Maksudnya:
name:
✅ "Budi"
✅ "Andi"
✅ null
Jadi tanda ? secara sederhana dapat dibaca:
“Variabel ini boleh null.”
7. Bagaimana dengan var?
Di transcript ada bagian yang perlu diluruskan.
Misalnya:
var x;
Dalam Dart modern, var bukan berarti secara umum “variabel yang bebas null”.
Yang perlu diperhatikan adalah tipe yang diinfer Dart dan konteks deklarasinya.
Contoh:
var x = 10;
Dart menyimpulkan:
x → int
Sehingga:
x = "Hello";
tidak diperbolehkan.
Untuk kode production Flutter, jangan menganggap var sebagai cara untuk “mematikan Null Safety”.
8. Bagaimana dengan dynamic?
dynamic memang lebih longgar.
Contoh:
dynamic x = null;
Ini valid.
Kemudian:
x = 10;
x = "Hello";
x = true;
juga bisa.
Karena dynamic memberi Dart lebih sedikit informasi mengenai tipe yang sebenarnya.
Contoh:
dynamic data = "Hello";
print(data.length);
Bisa bekerja.
Tetapi:
dynamic data = 10;
print(data.length);
bisa menghasilkan error saat runtime.
Jadi dalam aplikasi Flutter, jangan menggunakan dynamic sembarangan hanya supaya error hilang.
Lebih baik gunakan tipe yang jelas.
9. Kenapa Null Safety penting?
Ada beberapa keuntungan besar.
A. Mengurangi pengecekan null
Tanpa sistem tipe yang kuat, kita mungkin sering melakukan:
if (name != null) {
print(name.length);
}
atau berbagai pengecekan lainnya.
Dengan Null Safety, Dart membantu kita mengetahui:
“Variabel ini memang boleh null atau tidak?”
Sehingga banyak kesalahan dapat diketahui lebih awal, bahkan sebelum aplikasi dijalankan.
10. Membuat kode lebih aman
Misalnya:
String name = "Budi";
Dart tahu:
name tidak boleh null
Jadi kita bisa lebih yakin ketika melakukan:
print(name.length);
Sebaliknya:
String? name;
Dart tahu:
name mungkin null
Maka Dart tidak akan sembarangan mengizinkan kita memperlakukannya seperti String biasa.
11. Membantu optimasi kode
Sound Null Safety juga memberikan informasi tambahan kepada compiler mengenai kemungkinan null.
Informasi tipe yang lebih kuat dapat membantu compiler melakukan optimasi sehingga aplikasi dapat menghasilkan kode native yang lebih efisien.
Namun untuk pemula, jangan terlalu fokus pada bagian optimasi ini.
Yang paling penting adalah:
Null Safety membantu menemukan kesalahan null lebih awal dan membuat program lebih aman.
12. Konsep yang sangat penting: Nullable tidak bisa langsung diberikan ke Non-nullable
Perhatikan:
String? name = "Budi";
name adalah nullable.
Sekarang kita punya fungsi:
void printName(String name) {
print(name);
}
Parameter name di sini non-nullable.
Kemudian:
printName(name);
Dart akan mengeluh.
Kenapa?
Karena name memiliki tipe:
String?
sedangkan fungsi meminta:
String
Dart berpikir:
“Bagaimana kalau
nameternyata null?”
Ini adalah aturan penting:
String? ──X──> String
Nullable tidak boleh langsung digunakan sebagai non-nullable.
13. Cara pertama: cek menggunakan if
Ini cara yang paling aman dan jelas.
String? name = "Budi";
if (name != null) {
printName(name);
}
Di dalam blok if, Dart bisa mengetahui bahwa name tidak null.
Kalau:
name = null;
maka:
if (name != null)
tidak akan dijalankan.
Polanya
if (variable != null) {
// gunakan variable
}
Ini sangat sering digunakan dalam Flutter.
14. Cara kedua: gunakan ??
Operator:
??
dibaca sederhana sebagai:
“Kalau sebelah kiri null, gunakan nilai sebelah kanan.”
Contoh:
String? name;
String displayName = name ?? "Guest";
Kalau:
name == "Budi"
maka:
displayName = "Budi"
Kalau:
name == null
maka:
displayName = "Guest"
Jadi:
name ?? "Guest"
kurang lebih berarti:
kalau name tidak null
gunakan name
kalau name null
gunakan "Guest"
Ini sangat berguna.
Contoh Flutter:
Text(userName ?? "Guest")
15. Cara ketiga: Null assertion !
Ada operator:
!
Contoh:
String? name = "Budi";
printName(name!);
Tanda ! berarti:
“Saya yakin nilai ini tidak null.”
Sehingga:
name!
memperlakukan name sebagai non-nullable.
16. Tetapi hati-hati dengan !
Misalnya:
String? name = null;
printName(name!);
Kita mengatakan kepada Dart:
“Percayalah,
nametidak null.”
Padahal kenyataannya:
name = null
Akibatnya program dapat mengalami error saat runtime.
Jadi:
!
bukan berarti:
“ubah null menjadi nilai.”
Bukan.
! berarti:
“Saya menyatakan bahwa nilai ini tidak null.”
Kalau ternyata salah, program bisa error.
Karena itu gunakan ! sesedikit dan sebijak mungkin.
17. Perbandingan tiga cara
Misalnya:
String? name;
Kita ingin mengirimnya ke:
void printName(String name) {
print(name);
}
Cara 1 — pengecekan
if (name != null) {
printName(name);
}
Paling eksplisit dan aman.
Cara 2 — default value
printName(name ?? "Guest");
Kalau null → gunakan "Guest".
Cara 3 — assertion
printName(name!);
Kita yakin name tidak null.
18. Perbedaan ?? dan !
Ini sering membingungkan.
??
name ?? "Guest"
Artinya:
Kalau null, gunakan
"Guest".
Tidak menyebabkan error hanya karena name null.
!
name!
Artinya:
Saya yakin
nametidak null.
Kalau ternyata null → bisa error.
Jadi:
?? → punya alternatif
! → saya menjamin tidak null
19. Nullable List: ini bagian yang sangat penting
Transcript juga membahas List.
Ada dua konsep yang berbeda:
List<int?>
dan:
List<int>?
Jangan tertukar.
20. List<int?>
List<int?> numbers = [10, 20, null];
Artinya:
List-nya tidak null, tetapi isi di dalam List boleh null.
Visualisasinya:
List
├── 10
├── 20
└── null
Jadi:
numbers = [10, 20, null];
valid.
21. List<int>?
Sekarang:
List<int>? numbers;
Artinya:
List-nya sendiri boleh null.
Tetapi kalau List tersebut ada, semua item harus int.
Contoh:
numbers = [10, 20, 30];
valid.
Tetapi:
numbers = null;
juga valid.
Sedangkan:
numbers = [10, null, 30];
tidak valid.
22. Visualisasi perbedaannya
List<int?>
List
↓
[10, 20, null]
List ada, item boleh null.
List<int>?
List?
↓
null
List-nya boleh null, tetapi item di dalamnya tidak boleh null.
List<int?>?
Bahkan kita bisa memiliki:
List<int?>? numbers;
Artinya:
List boleh null, dan kalau List ada, item-itemnya juga boleh null.
Jadi:
null
atau:
[10, null, 20]
keduanya bisa valid.
23. Null Safety pada parameter fungsi
Null Safety juga berlaku pada function.
Misalnya:
void greet(String name) {
print("Hello $name");
}
name non-nullable.
Berarti:
greet("Budi");
valid.
Tetapi konsep:
greet(null);
tidak valid.
Kalau memang function boleh menerima null:
void greet(String? name) {
print(name);
}
Sekarang:
greet("Budi");
greet(null);
keduanya diperbolehkan.
24. Null Safety pada return value
Null Safety juga berlaku pada nilai yang dikembalikan function.
Contoh:
String getName() {
return "Budi";
}
Function ini menjanjikan:
Saya akan mengembalikan
String, bukan null.
Kalau function memang mungkin tidak menemukan data:
String? getName() {
return null;
}
Tanda ? memberitahu pemanggil:
“Hati-hati, hasil function ini mungkin null.”
Ini sangat umum ketika mengambil data dari database, API, atau proses pencarian.
25. Kenapa nullable sering dibutuhkan dalam Flutter?
Bayangkan kita mengambil data user dari server.
String? username = getUsernameFromServer();
Kita belum tentu mendapatkan username.
Kemungkinannya:
Server menemukan user
↓
"budi"
atau
Server tidak menemukan user
↓
null
Karena itu tipe yang masuk akal adalah:
String?
Kemudian:
Text(username ?? "Guest")
Kalau username ada:
Budi
Kalau null:
Guest
Ini pola yang sangat umum di Flutter.
26. Sekarang masuk ke late
Bagian terakhir video membahas keyword:
late
Ini juga penting dalam Dart.
late secara sederhana dapat dipahami sebagai:
“Variabel ini non-nullable, tetapi saya akan memberinya nilai nanti.”
Contoh:
late String name;
Perhatikan:
String
berarti tidak boleh null.
Tetapi kita belum mengisinya.
Biasanya Dart akan meminta variabel non-nullable diinisialisasi.
Dengan late, kita mengatakan:
“Tenang, saya akan mengisinya sebelum digunakan.”
27. Contoh late
late String name;
name = "Budi";
print(name);
Ini valid.
Urutannya:
1. Deklarasikan name
↓
2. name belum memiliki nilai
↓
3. Berikan "Budi"
↓
4. Gunakan name
28. Jangan menggunakan late lalu lupa mengisinya
Contoh:
late String name;
print(name);
Ini bermasalah.
Karena kita sudah mengatakan:
“
namenanti akan saya isi.”
Tetapi ternyata kita langsung menggunakannya tanpa memberikan nilai.
Dart akan menghasilkan error saat runtime berupa LateInitializationError.
Jadi:
late
bukan berarti variabel otomatis mempunyai nilai.
29. Kenapa late berguna pada class?
Misalnya:
class Person {
String name;
int age;
}
Ini bermasalah karena name dan age non-nullable tetapi belum diinisialisasi.
Salah satu solusi adalah constructor:
class Person {
String name;
int age;
Person(this.name, this.age);
}
Kemudian:
final person = Person("Budi", 25);
Constructor memberikan nilai kepada:
name → "Budi"
age → 25
30. Solusi lain: required
Kalau menggunakan named parameters:
class Person {
String name;
int age;
Person({
required this.name,
required this.age,
});
}
Sekarang ketika membuat object:
final person = Person(
name: "Budi",
age: 25,
);
required memastikan argument tersebut harus diberikan.
31. Lalu kapan late digunakan?
Misalnya nilai tidak tersedia ketika object dibuat.
Contoh sederhana:
class Person {
late String name;
late int age;
void initialize() {
name = "Budi";
age = 25;
}
}
Kita bisa memberikan nilai kemudian.
Dalam Flutter, konsep late juga sering ditemui ketika sebuah nilai baru bisa dibuat setelah proses tertentu.
Contoh:
late TextEditingController controller;
Kemudian:
controller = TextEditingController();
Namun dalam Flutter, lifecycle dan tempat inisialisasinya harus diperhatikan.
32. late juga berhubungan dengan lazy initialization
Ada penggunaan lain:
late String name = getName();
Dengan late, initializer tersebut dapat ditunda sampai variabel benar-benar pertama kali digunakan.
Konsepnya:
Program mulai
↓
getName() belum tentu langsung dijalankan
↓
name pertama kali digunakan
↓
getName() dijalankan
↓
hasil disimpan
Inilah yang disebut lazy initialization.
Tetapi jangan menganggap semua penggunaan late otomatis seperti ini; late tanpa initializer dan late dengan initializer memiliki perilaku yang berbeda.
33. Bedakan late dengan nullable
Ini bagian yang sangat penting.
Nullable
String? name;
Artinya:
nameboleh null.
late
late String name;
Artinya:
nametidak boleh null, tetapi nilainya diberikan nanti.
Jadi:
String? name
↓
boleh null
late String name
↓
tidak boleh null,
tetapi boleh diinisialisasi nanti
34. Analogi sederhana
Bayangkan kamu punya dua kotak.
Kotak pertama
String? name;
Kamu berkata:
“Kotak ini boleh kosong.”
Jadi:
[ kosong ]
diperbolehkan.
Kotak kedua
late String name;
Kamu berkata:
“Kotak ini tidak boleh kosong ketika digunakan, tetapi saya belum siap memasukkannya sekarang.”
Kemudian sebelum digunakan:
name = "Budi";
Baru aman.
Kalau kamu menggunakan kotak kedua ketika masih kosong:
print(name);
→ error.
35. Ringkasan simbol yang harus kamu hafalkan
| Kode | Arti |
|---|---|
String | Tidak boleh null |
String? | Boleh null |
?? | Kalau null, gunakan nilai alternatif |
??= | Isi nilai hanya jika sekarang null |
?. | Akses member hanya jika tidak null |
! | Saya yakin ini tidak null |
late | Akan diinisialisasi nanti |
required | Parameter wajib diberikan |
Contoh:
String? name;
name ??= "Guest";
print(name?.length);
36. Memahami ?.
Misalnya:
String? name;
Kita tidak bisa sembarangan:
print(name.length);
Karena name mungkin null.
Gunakan:
print(name?.length);
Artinya:
Kalau
nametidak null, ambillength. Kalau null, hasilnya null.
Contoh:
String? name = "Budi";
print(name?.length);
Output:
4
Kalau:
String? name = null;
print(name?.length);
hasilnya:
null
37. ?. + ?? sangat sering digunakan bersama
Contoh:
String? name;
final length = name?.length ?? 0;
Cara membacanya:
name?.length
↓
kalau name ada → ambil length
kalau name null → hasil null
kemudian
?? 0
↓
kalau hasilnya null → gunakan 0
Jadi hasil akhirnya:
length = 0
Ini pola yang sangat berguna dalam Flutter.
38. Contoh nyata dalam Flutter
Misalnya:
String? username;
Kita ingin menampilkan username.
Cara aman:
Text(username ?? "Guest")
Artinya:
username ada?
↓
YA → tampilkan username
↓
TIDAK → tampilkan "Guest"
Atau:
Text(user?.name ?? "Guest")
Artinya:
user ada?
↓
YA → ambil user.name
↓
TIDAK → "Guest"
Ini adalah pola yang akan sangat sering kamu temui saat belajar Flutter.
39. Satu hal penting: null bukan berarti 0
Pemula sering keliru menganggap:
null = 0
Padahal berbeda.
null → tidak ada nilai
0 → ada nilai, yaitu angka nol
Contoh:
int? age = null;
berbeda dengan:
int age = 0;
Yang pertama:
umur belum diketahui/tidak tersedia.
Yang kedua:
umur diketahui dan nilainya 0.
40. null juga bukan String kosong
Ini juga berbeda:
String? name = null;
dan:
String name = "";
Perbedaannya:
null → tidak ada String
"" → ada String, tetapi panjangnya 0
Contoh:
print(name?.length);
Kalau name = null:
null
Kalau:
name = "";
hasilnya:
0
41. Kesalahan transcript yang perlu kamu ingat
Ada beberapa istilah dalam transcript yang terdengar seperti “non-variable”, “invaluable”, atau “malleable”. Itu kemungkinan besar hasil speech-to-text yang salah.
Istilah Dart yang benar adalah:
Non-nullable
String name;
Tidak boleh null.
Nullable
String? name;
Boleh null.
Jadi jangan sampai kamu menghafal istilah:
“non-variable” atau “invaluable variable”
Istilah yang benar adalah non-nullable dan nullable.
42. Gambaran besar Null Safety
Kalau diringkas, pola pikirnya seperti ini:
NULL SAFETY
│
┌───────────┴───────────┐
│ │
NON-NULLABLE NULLABLE
│ │
String String?
int int?
bool bool?
│ │
tidak boleh null boleh null
Kalau punya nullable:
String?
│
├── if (x != null)
│
├── x ?? defaultValue
│
├── x?.property
│
└── x! ← hati-hati
Dan kalau memang ingin menginisialisasi non-nullable nanti:
late String name;
43. Cheat sheet paling penting
Kalau baru belajar, hafalkan pola berikut:
// 1. Tidak boleh null
String name = "Budi";
// 2. Boleh null
String? name;
// 3. Default value jika null
String displayName = name ?? "Guest";
// 4. Akses property dengan aman
print(name?.length);
// 5. Mengatakan "saya yakin tidak null"
print(name!.length);
// 6. Isi hanya jika masih null
name ??= "Guest";
// 7. Non-nullable tapi diisi nanti
late String username;
username = "Budi";
Dan yang paling penting:
String
↓
tidak boleh null
String?
↓
boleh null
?
↓
nullable
??
↓
fallback/default
?.
↓
akses dengan aman jika tidak null
!
↓
saya menjamin tidak null
late
↓
akan diisi nanti
Inti video dalam satu kalimat
Null Safety di Dart adalah sistem tipe yang membuat kita secara eksplisit membedakan nilai yang boleh null (String?) dan yang tidak boleh null (String), sehingga banyak kesalahan akibat null dapat diketahui lebih awal dan kode menjadi lebih aman.
Kalau kamu sedang belajar Flutter dari nol, kuasai String vs String?, ??, ?., !, dan late terlebih dahulu. Lima konsep ini akan muncul berkali-kali ketika nanti masuk ke class, constructor, API/JSON, Future, State Management, dan widget Flutter.