Tampilan
Kenapa penting
List bagus untuk data berurutan, tetapi banyak pertanyaan di backend berbentuk lain: "SKU ini produk apa?", "pengguna ini sudah pernah klaim voucher?", "berapa pesanan per status hari ini?". Menjawabnya dengan loop di List berarti memeriksa elemen satu per satu — lambat dan rawan bug. Set menjawab pertanyaan keanggotaan dan keunikan, sedangkan Map menjawab pencarian berdasarkan kunci. Cache, index produk, penghitung statistik, dan konfigurasi aplikasi hampir selalu dibangun di atas Map.
Konsep inti
Set: kumpulan nilai unik
Set adalah collection yang tidak menyimpan duplikat. Menambahkan nilai yang sudah ada tidak mengubah apa pun, dan add mengembalikan false. Ada tiga implementasi utama yang berbeda dalam urutan:
java
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
public class SetDemo {
public static void main(String[] args) {
List<String> tags = List.of("promo", "kopi", "promo", "arabika", "kopi");
Set<String> unique = new HashSet<>(tags);
System.out.println(unique.size() + " " + unique.contains("promo") + " " + unique.contains("teh"));
System.out.println(unique.add("kopi") + " " + unique.add("teh"));
Set<String> inOrder = new LinkedHashSet<>(tags); // urutan kemunculan pertama
Set<String> sorted = new TreeSet<>(tags); // urutan alfabet
System.out.println(inOrder);
System.out.println(sorted);
}
}Output:
text
3 true false
false true
[promo, kopi, arabika]
[arabika, kopi, promo]HashSet— paling cepat untukadddancontains, tetapi urutan iterasinya tidak dijamin. Karena itu contoh di atas tidak mencetak isinya langsung.LinkedHashSet— sedikit lebih berat, tetapi mempertahankan urutan kemunculan pertama.TreeSet— selalu terurut (alfabetis untukString, kecil ke besar untuk angka).
Set tidak punya indeks: tidak ada get(i). Ia untuk menjawab "ada atau tidak?" dan untuk membuang duplikat.
Map: pasangan kunci–nilai
Map<K, V> menyimpan pasangan kunci (key) dan nilai (value). Kunci unik; nilai boleh sama. Map<String, Integer> berarti kuncinya String dan nilainya Integer.
java
import java.util.Map;
import java.util.TreeMap;
public class MapDemo {
public static void main(String[] args) {
Map<String, Integer> stock = new TreeMap<>(); // kunci: SKU, nilai: jumlah stok
stock.put("KOPI-250", 12);
stock.put("TEH-100", 0);
stock.put("GULA-500", 7);
System.out.println(stock.get("KOPI-250"));
System.out.println(stock.get("SUSU-1L"));
System.out.println(stock.getOrDefault("SUSU-1L", 0));
System.out.println(stock.containsKey("TEH-100"));
Integer old = stock.put("KOPI-250", 10); // kunci sama → nilai lama diganti
System.out.println(old + " → " + stock.get("KOPI-250"));
stock.putIfAbsent("GULA-500", 99); // sudah ada → tidak diubah
stock.putIfAbsent("SUSU-1L", 5); // belum ada → ditambahkan
stock.remove("TEH-100");
for (Map.Entry<String, Integer> entry : stock.entrySet()) {
System.out.println(entry.getKey() + " = " + entry.getValue());
}
System.out.println(stock.keySet() + " " + stock.values());
}
}Output:
text
12
null
0
true
12 → 10
GULA-500 = 7
KOPI-250 = 10
SUSU-1L = 5
[GULA-500, KOPI-250, SUSU-1L] [7, 10, 5]| Method | Fungsi |
|---|---|
put(k, v) | simpan; bila kunci sudah ada, ganti nilai dan kembalikan yang lama |
get(k) | ambil nilai, atau null bila kunci tidak ada |
getOrDefault(k, d) | ambil nilai, atau d bila kunci tidak ada |
containsKey(k) | apakah kunci ada |
putIfAbsent(k, v) | simpan hanya bila kunci belum ada |
remove(k) | hapus entri berdasarkan kunci |
entrySet(), keySet(), values() | pasangan, kunci saja, nilai saja — untuk iterasi |
Untuk mengiterasi kunci sekaligus nilainya, pakai entrySet(): setiap elemennya bertipe Map.Entry<K, V> dengan getKey() dan getValue(). Ini lebih efisien daripada iterasi keySet() lalu memanggil get untuk setiap kunci.
Seperti Set, ada tiga implementasi dengan perilaku urutan yang sama: HashMap (tercepat, urutan tidak dijamin), LinkedHashMap (urutan penyisipan), dan TreeMap (urut kunci). LinkedHashMap dan TreeMap juga mendukung method sequenced Java 21 seperti firstEntry() dan lastEntry().
Pola penting: menghitung frekuensi
Menghitung kemunculan — pesanan per status, error per endpoint, kata per dokumen — adalah pola Map yang paling sering muncul:
java
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class OrderStats {
public static void main(String[] args) {
List<String> statuses = List.of("PAID", "NEW", "PAID", "SHIPPED", "PAID", "NEW");
Map<String, Integer> counts = new LinkedHashMap<>();
for (String status : statuses) {
counts.put(status, counts.getOrDefault(status, 0) + 1);
}
System.out.println(counts);
}
}Output: {PAID=3, NEW=2, SHIPPED=1}. getOrDefault(status, 0) mengembalikan 0 untuk status yang belum pernah muncul, sehingga tidak perlu if terpisah. (Ada cara yang lebih ringkas dengan merge dan lambda — dibahas di M04.)
Map.of dan null
Map.of("KOPI-250", 2, "GULA-500", 1) membuat map immutable, sama seperti List.of: put melempar UnsupportedOperationException, kunci ganda ditolak (IllegalArgumentException: duplicate key), null ditolak, dan urutan iterasinya tidak dijamin. Map.of menerima paling banyak 10 pasangan; untuk lebih banyak, pakai Map.ofEntries(Map.entry(k, v), ...).
HashMap dan LinkedHashMap mengizinkan satu kunci null dan nilai null, sedangkan TreeMap menolak kunci null. Hindari menyimpan null sebagai nilai: get yang mengembalikan null jadi ambigu — kuncinya tidak ada, atau nilainya memang null?
Memilih struktur yang tepat
| Kebutuhan | Pilihan |
|---|---|
| Daftar berurutan, boleh duplikat, akses indeks | ArrayList |
| Nilai unik, cek "sudah ada?" secepat mungkin | HashSet |
| Nilai unik, urutan kemunculan dipertahankan | LinkedHashSet |
| Nilai unik, selalu terurut | TreeSet |
| Cari nilai berdasarkan kunci (ID, SKU, email) | HashMap |
Seperti HashMap, tapi urutan penyisipan tetap | LinkedHashMap |
| Kunci selalu terurut (laporan, rentang) | TreeMap |
Bagaimana HashSet dan HashMap memutuskan dua object "sama"? Mereka memakai method equals dan hashCode milik elemen atau kuncinya. Untuk String dan wrapper sudah benar; untuk class buatanmu sendiri ada aturannya — dibahas di bab equals & hashCode.
Contoh di dunia backend
Katalog produk dimuat sekali ke memori, lalu dicari berdasarkan SKU setiap kali keranjang dihitung. Map menjadi index: pencarian tidak perlu menelusuri seluruh produk. putIfAbsent sekaligus dipakai untuk menolak SKU ganda saat katalog dibuat.
java
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
record Product(String sku, String name, long price) {}
public class ProductCatalog {
private final Map<String, Product> bySku = new LinkedHashMap<>();
ProductCatalog(List<Product> products) {
for (Product product : products) {
if (bySku.putIfAbsent(product.sku(), product) != null) {
throw new IllegalArgumentException("SKU ganda: " + product.sku());
}
}
}
Product find(String sku) {
return bySku.get(sku); // cepat, tanpa menelusuri seluruh produk
}
long totalPrice(Map<String, Integer> cart) { // kunci: SKU, nilai: jumlah
long total = 0;
for (Map.Entry<String, Integer> line : cart.entrySet()) {
Product product = bySku.get(line.getKey());
if (product == null) {
throw new IllegalArgumentException("Produk tidak dikenal: " + line.getKey());
}
total += product.price() * line.getValue();
}
return total;
}
public static void main(String[] args) {
ProductCatalog catalog = new ProductCatalog(List.of(
new Product("KOPI-250", "Kopi Gayo 250 g", 85_000),
new Product("TEH-100", "Teh Melati 100 g", 40_000),
new Product("GULA-500", "Gula Aren 500 g", 30_000)));
System.out.println(catalog.find("TEH-100"));
System.out.println(catalog.find("SUSU-1L"));
System.out.println(catalog.totalPrice(Map.of("KOPI-250", 2, "GULA-500", 1)));
}
}Output:
text
Product[sku=TEH-100, name=Teh Melati 100 g, price=40000]
null
200000putIfAbsent mengembalikan nilai lama bila kunci sudah ada — di sini dimanfaatkan untuk mendeteksi SKU ganda. Pola "muat sekali ke Map, lalu cari berdasarkan ID" juga dipakai untuk cache sederhana di service. Di aplikasi multi-thread seperti server web, cache yang ditulis bersamaan butuh ConcurrentHashMap — topik level berikutnya.
Pertanyaan interview
1. Apa beda HashMap, LinkedHashMap, dan TreeMap?
Ketiganya menyimpan pasangan kunci–nilai dengan kunci unik. HashMap paling cepat untuk get/put tetapi tidak menjamin urutan iterasi. LinkedHashMap mempertahankan urutan penyisipan. TreeMap menjaga kunci selalu terurut (lebih lambat sedikit, dan menolak kunci null). Pilih berdasarkan kebutuhan urutan.
2. Kapan memakai Set dibanding List?
Pakai Set bila yang penting adalah keunikan dan pertanyaan "apakah X ada?" — misalnya daftar user yang sudah klaim voucher. HashSet.contains jauh lebih cepat daripada List.contains yang memeriksa elemen satu per satu. Pakai List bila urutan dan duplikat penting, atau butuh akses berdasarkan indeks.
3. Apa yang terjadi bila get dipanggil dengan kunci yang tidak ada?
get mengembalikan null. Bila hasilnya langsung disimpan ke primitif (int), unboxing memicu NullPointerException. Gunakan getOrDefault, cek containsKey, atau periksa null sebelum memakai hasilnya.
Jebakan umum
- Mengandalkan urutan
HashMap/HashSet. Urutannya bisa berbeda antarversi Java dan antarisi data. PakaiLinkedHashMap/TreeMapbila urutan penting. - Unboxing hasil
getyangnull.int qty = map.get(key);→NullPointerExceptionbila kunci tidak ada. - Iterasi
keySet()lalugetdi setiap putaran. PakaientrySet(). - Mengubah map dari
Map.of→UnsupportedOperationException. Salin kenew HashMap<>(...)bila perlu diubah. - Menyimpan
nullsebagai nilai. Membuatgetambigu; simpan nilai default atau jangan simpan entrinya. - Memakai class buatan sendiri sebagai kunci tanpa
equals/hashCodeyang benar — kunci "sama" tidak ketemu. Dibahas di bab equals & hashCode.
Ringkasan
Setmenyimpan nilai unik:HashSet(cepat, tanpa urutan),LinkedHashSet(urutan kemunculan),TreeSet(urut).Mapmenyimpan pasangan kunci–nilai dengan kunci unik;putdengan kunci yang sama mengganti nilainya.getmengembalikannullbila kunci tidak ada;getOrDefaultdancontainsKeymencegahNullPointerException.- Iterasi map lewat
entrySet(); polagetOrDefault(k, 0) + 1untuk menghitung frekuensi. Map.ofimmutable;HashMap/LinkedHashMap/TreeMapdipilih berdasarkan kebutuhan urutan.- Kesamaan elemen
Setdan kunciMapditentukanequalsdanhashCode.