Pernah nggak, aplikasi kamu tiba-tiba crash gara-gara satu nilai null yang "nyasar"? Rasanya seperti sudah masak mie instan sempurna, eh ternyata garamnya ketinggalan. Menyebalkan, kan? Nah, itulah masalah klasik yang diselesaikan oleh null safety generics Dart — dua fitur andalan yang membuat kode kamu lebih aman, lebih fleksibel, dan jauh lebih profesional. Di artikel ke-10 dari seri Dart from Zero to Zorro ini, kita akan bedah tuntas kedua konsep tersebut dengan cara yang menyenangkan dan langsung bisa kamu praktikkan!
🛡️ Null Safety di Dart — Bodyguard Kode Kamu
Bayangkan kamu punya dompet. Normalnya, dompet itu berisi uang. Tapi suatu hari, seseorang mengambil uangnya tanpa bilang apa-apa — dan kamu tetap mencoba membayar kopi dengan dompet kosong itu. Hasilnya? Malu di kasir. Itulah analogi null dalam pemrograman.
Di Dart versi lama, semua variabel bisa bernilai null tanpa peringatan. Dart 2.12+ hadir dengan Sound Null Safety yang memaksa kamu untuk eksplisit: apakah variabel ini boleh null? Atau tidak?
📌 Konsep Kunci
Dengan Null Safety, tipe data dibagi dua:
• String → tidak bisa null (non-nullable)
• String? → boleh null (nullable) — harus ditangani eksplisit
🎯 Contoh Null Safety Dasar
void main() {
String nama = 'Zorro'; // ✅ non-nullable, amanString? kota; // nullable, boleh null// Langsung pakai 'nama' — aman, pasti ada nilainya
print(nama.toUpperCase()); // Output: ZORRO// Harus cek dulu sebelum pakai 'kota'if (kota != null) {
print(kota.toUpperCase());
} else {
print('Kota belum diisi!');
}
}
💡 TIPS — Null-Aware Operators
Dart punya operator khusus untuk handle nullable dengan ringkas:
• ?? → nilai default jika null | ?. → safe call | ! → force unwrap (hati-hati!)
⚡ Null-Aware Operators dalam Aksi
void main() {
String? username;
// ?? → pakai nilai default jika nullString tampilan = username ?? 'Guest';
print(tampilan); // Output: Guest// ?. → safe call, tidak crash walau null
print(username?.length); // Output: null (bukan crash)// ??= → assign hanya jika masih null
username ??= 'ZorroCoder';
print(username); // Output: ZorroCoder
}
🧬 Generics di Dart — Satu Fungsi untuk Semua Tipe
Bayangkan kamu punya kotak penyimpanan ajaib. Kotak itu bisa menampung apapun — buku, sepatu, laptop — tapi saat kamu mengambilnya, kamu sudah tahu persis apa yang kamu ambil tanpa harus menebak-nebak. Itulah inti dari Generics dalam null safety generics Dart!
Tanpa generics, kamu terpaksa menulis fungsi yang sama berulang kali hanya karena tipe datanya berbeda. Dengan generics, kamu tulis sekali, pakai berkali-kali — tetap aman dari sisi tipe.
🔥 FAKTA MENARIK
List, Map, dan Set di Dart sudah menggunakan Generics di balik layar! Saat kamu menulis List<String>, kamu sudah pakai Generics tanpa sadar. 🎉
Generics juga bisa diterapkan pada class. Misalnya, kamu ingin membuat kotak pembungkus (wrapper) yang bisa menampung tipe data apapun:
📦 Generic Class — Kotak Ajaib
classKotakAjaib<T> {
T isi;
KotakAjaib(this.isi);
void tampilkan() {
print('Isi kotak: $isi');
}
}
void main() {
var kotakAngka = KotakAjaib<int>(42);
kotakAngka.tampilkan(); // Isi kotak: 42var kotakKata = KotakAjaib<String>('Zorro adalah Dart Master');
kotakKata.tampilkan(); // Isi kotak: Zorro adalah Dart Master
}
⚡ INSIGHT PENTING — Type Parameter Naming
Konvensi umum: T untuk tipe umum, K untuk key, V untuk value, E untuk element. Kamu juga bebas menggunakan nama yang lebih deskriptif seperti TData atau TResult.
⚔️ Combo Maut: null safety generics Dart Bersatu
Ketika Generics dan Null Safety digabungkan, hasilnya adalah kode yang sekaligus fleksibel dan aman. Kamu bisa mendefinisikan generic type yang boleh null atau tidak — sesuai kebutuhan.
📋 Panduan: Membuat Generic Repository yang Null-Safe
1
Definisikan interface / abstract class dengan Generic
Buat kontrak yang bisa dipakai untuk tipe data apapun menggunakan parameter tipe T.
2
Tentukan apakah return type boleh null
Gunakan T? jika operasi mungkin gagal/tidak menemukan data (seperti fungsi findById).
3
Implementasikan concrete class
Buat kelas konkret yang mengimplementasikan abstract class tadi dengan tipe data spesifik.
4
Handle null result dengan ?? atau if-check
Selalu tangani kemungkinan null sebelum menggunakan hasilnya agar kode tetap aman di runtime.
🔥 Generic Repository + Null Safety
// Step 1: Abstract class dengan Genericabstract classRepository<T> {
void simpan(T item);
T? cari(int id); // T? → mungkin null jika tidak ketemuList<T> semuaData();
}
// Step 3: Implementasi konkretclassUserRepositoryimplements Repository<String> {
finalMap<int, String> _db = {};
@overridevoid simpan(String item) => _db[_db.length] = item;
@overrideString? cari(int id) => _db[id]; // bisa null jika id tidak ada@overrideList<String> semuaData() => _db.values.toList();
}
void main() {
var repo = UserRepository();
repo.simpan('Zorro');
repo.simpan('Dart Fan');
// Step 4: Handle null dengan ??String user = repo.cari(0) ?? 'User tidak ditemukan';
print(user); // ZorroString ghost = repo.cari(99) ?? 'User tidak ditemukan';
print(ghost); // User tidak ditemukan
}
⚠️ PERHATIAN — Hindari Force Unwrap Sembarangan!
Operator ! (force unwrap) akan crash jika nilainya ternyata null! Gunakan hanya ketika kamu benar-benar yakin nilainya tidak null — misalnya setelah melakukan null check eksplisit. Jangan terlalu banyak pakai ! hanya untuk "diam-in" compiler warning ya! 😅
📊 Tabel Referensi — Null Safety Generics Dart
🔬 ANALYSIS — Kapan Pakai Apa?
Situasi
Gunakan
Contoh
Variabel pasti ada nilainya
String
String nama = 'Zorro'
Variabel mungkin tidak ada
String?
String? kota
Fungsi untuk berbagai tipe
Generic <T>
T ambil<T>(List<T> list)
Beri nilai default jika null
?? operator
nama ?? 'Guest'
Akses method tanpa crash
?. safe call
nama?.length
Batasi tipe pada Generic
extends bound
<T extends num>
Kamu juga bisa membatasi jenis tipe yang boleh digunakan pada Generic dengan kata kunci extends:
🔒 Bounded Type Parameter
// T hanya boleh berupa tipe num (int, double, dll)
T penjumlahan<T extends num>(T a, T b) {
return (a + b) as T;
}
void main() {
print(penjumlahan(10, 20)); // 30 (int)
print(penjumlahan(1.5, 2.5)); // 4.0 (double)// penjumlahan('a', 'b') → ERROR! String bukan num ✅
}
💡 TIPS — Late Variables
Kalau kamu yakin variabel pasti akan diinisialisasi sebelum dipakai tapi belum bisa diisi saat deklarasi, gunakan keyword late: late String username; — Dart tidak akan protes saat deklarasi, tapi akan crash jika diakses sebelum diisi. Gunakan dengan bijak!
📚
Bagian dari
Seri Belajar Dart: Dart from Zero to Zorro
Artikel ini adalah bagian ke-10 dari 16 artikel seri lengkap belajar Dart dari nol hingga mahir. Kunjungi halaman utama seri untuk melihat semua artikel!
Di artikel ini, kita sudah tuntas membahas dua fitur super penting dalam dunia null safety generics Dart:
🛡️
Null Safety memastikan kamu tidak bisa "lupa" menangani nilai null — compiler akan mengingatkan sebelum runtime crash.
🧬
Generics membuat kode lebih reusable — satu fungsi atau class bisa bekerja untuk berbagai tipe data tanpa mengorbankan keamanan tipe.
⚔️
Kombinasi keduanya menghasilkan kode yang sekaligus fleksibel dan aman — seperti punya bodyguard sekaligus asisten serba bisa.
🔧
Operator null-aware (??, ?., ??=) membuat penanganan null jadi lebih elegan dan ringkas.
Artikel selanjutnya kita akan melompat ke dunia Flutter — framework UI lintas platform buatan Google yang dibangun di atas Dart. Siap? 🚀
💬 Bagikan Pengalamanmu!
Sudah coba praktik null safety dan generics? Punya pertanyaan atau kesulitan? Drop komentarmu di bawah — kita diskusi bareng! Dan kalau artikel ini bermanfaat, jangan lupa share ke teman belajar kamu ya! 🙌
saifiahmada.com adalah blog belajar programming Indonesia, membahas lengkap materi bahasa pemrograman: code HTML, CSS, Bootstrap, Desain, PHP, MySQL, coding Java, Query, SQL, dan dunia linux
No comments:
Post a Comment