Map
Pasangan key-value: membuat, mengakses, dan mengolah Map.
Data berpasangan: kunci dan nilai
List menyimpan nilai berurutan, Set menyimpan nilai unik. Tapi bagaimana menyimpan "nama → Budi", "umur → 17"? Data dunia nyata sering berbentuk pasangan kunci-nilai: kamus kata-arti, username-password, kode pos-kota. Map adalah koleksi untuk itu.
Analogi: map itu seperti kamus. Kamu tidak mencari arti kata dengan memindai semua halaman (seperti list), kamu langsung buka berdasarkan kata kunci (key) dan dapat artinya (value).
Kenapa Map ada?
Karena pencarian berdasarkan kunci adalah kebutuhan universal: data pengguna berdasarkan ID, konfigurasi berdasarkan nama, cache berdasarkan URL. Map memberi akses langsung O(1) ke nilai lewat kuncinya, tanpa loop.
Membuat dan memakai Map
void main() {
// Map<String, String>: kunci String, nilai String
Map<String, String> kamus = {
'apel': 'apple',
'mangga': 'mango',
};
print(kamus['apel']); // apple, akses lewat kunci
print(kamus['durian']); // null, kunci tidak ada
kamus['pisang'] = 'banana'; // tambah pasangan baru
kamus['apel'] = 'APPLE'; // timpa nilai kunci yang ada
print(kamus);
print(kamus.keys); // (apel, mangga, pisang)
print(kamus.values); // (APPLE, mango, banana)
print(kamus.length); // 3
}Poin penting: mengakses kunci yang tidak ada menghasilkan null, bukan error. Itu sebabnya tipe hasilnya nullable dan sering dipadukan dengan ??.
Contoh kedua, map dengan tipe nilai campuran untuk data pengguna:
void main() {
Map<String, dynamic> user = {
'nama': 'Budi',
'umur': 17,
'aktif': true,
'hobi': ['membaca', 'ngoding'],
};
print('Nama: ${user['nama']}');
print('Hobi pertama: ${user['hobi'][0]}');
// Iterasi semua pasangan
user.forEach((kunci, nilai) {
print('$kunci => $nilai');
});
user.remove('aktif'); // hapus pasangan
print(user.containsKey('aktif')); // false
}Map<String, dynamic> sangat umum untuk data JSON dari API. Nilai dynamic artinya "tipe apa pun", fleksibel tapi butuh kehati-hatian.
Kunci harus unik
void main() {
var m = {'a': 1, 'b': 2};
m['a'] = 99; // kunci 'a' sudah ada: nilainya DITIMPA, bukan dobel
print(m); // {a: 99, b: 2}
print(m.length); // 2, tidak bertambah
}Seperti Set, kunci map bersifat unik. Menulis ke kunci yang sama menimpa nilai lama. Ini fitur, bukan bug: cache[url] = data selalu menyimpan versi terbaru.
Kesalahan umum
1. Lupa hasil akses bisa null
// SALAH: crash jika kunci tidak ada
void main() {
var kamus = {'apel': 'apple'};
// print(kamus['durian']!.length); // ERROR: null!
}// BENAR: sediakan default dengan ??
void main() {
var kamus = {'apel': 'apple'};
print(kamus['durian'] ?? 'tidak ada'); // tidak ada
print(kamus['apel']?.length); // 5, aman dengan ?.
}2. Salah tipe kunci
// SALAH
void main() {
var m = {1: 'satu', 2: 'dua'}; // Map<int, String>
// print(m['1']); // null! '1' String != 1 int
print(m[1]); // satu
}Kunci 1 (int) dan '1' (String) adalah dua kunci berbeda. Konsistenlah dengan tipe kunci.
3. Mengubah map saat diiterasi
// SALAH: error ConcurrentModificationError
void main() {
var m = {'a': 1, 'b': 2};
// for (var k in m.keys) {
// m.remove(k);
// }
}// BENAR: iterasi salinan kunci dulu
void main() {
var m = {'a': 1, 'b': 2};
for (var k in m.keys.toList()) {
m.remove(k);
}
print(m); // {}
}Kesimpulan
Map = pasangan kunci-nilai unik, akses map[kunci] menghasilkan null jika tak ada (pakai ??), kunci bersifat unik dan menimpa. Map<String, dynamic> adalah jembatan utama ke data JSON.
Catatan teknis: Di balik layar, Map memakai hash table seperti Set, sehingga akses kunci O(1). Iterasi map mengikuti urutan penyisipan (insertion order) di implementasi default LinkedHashMap.
Tantangan
Kasir sederhana
Diberi Map harga barang dan list belanjaan, hitung total bayar. Pakai ?? 0 agar barang yang tidak ada di harga tidak error.
void main() {
var harga = {'nasi': 5000, 'ayam': 8000, 'es teh': 3000};
var belanja = ['nasi', 'ayam', 'ayam', 'kerupuk'];
// TODO: hitung total
}