Seluruh struktur yang kita jelajahi sejauh ini — List, Set, Queue, Deque — menyimpan elemen satu per satu dan semuanya mewarisi Collection. Ada satu keluarga kebutuhan yang tidak terjawab oleh struktur tersebut: mencari nilai berdasarkan penanda tertentu. Stok toko perlu menjawab “berapa jumlah Pensil?” tanpa menyisir daftar; daftar nilai siswa perlu memetakan nama ke angka; statistik kata perlu tahu berapa kali java muncul. Kebutuhan-kebutuhan itu dijawab oleh interface Map, struktur yang memasangkan key (penanda unik) dengan value (nilai yang dicari). Pada Chapter ini kita pelajari kontrak dasarnya, tiga cara memandang isinya, dan method modern yang membuat pola hitung frekuensi menjadi ringkas.
Key dan Value dalam Satu Kontrak #
Kontrak Map sederhana namun tegas: satu key paling banyak memetakan ke satu value. Memasang key yang sudah ada lewat put tidak menambah baris baru — nilai lama diganti dan dikembalikan sebagai hasil put, sehingga kita bisa tahu nilai sebelumnya yang terganti. Operasi pencarian (get, containsKey) bekerja pada key, bukan pada value, karena key adalah alamat datanya.
Map berdiri di luar hierarki Collection — Map tidak meng-extend Collection. Alasannya struktural: method add(E e) milik Collection tidak punya makna untuk pasangan key-value, sedangkan Collection memproses satu elemen per operasi. Meski begitu, Map tetap menyediakan jembatan ke dunia iterasi lewat tiga pandangan yang dibahas setelah contoh pertama.
Operasi Dasar Map #
Program berikut memakai Map<String, Integer> untuk stok toko: key berupa nama barang, value berupa jumlahnya. Kita menjajal seluruh operasi inti kontrak Map satu per satu:
import java.util.*;
public class StokToko {
public static void main(String[] args) {
Map<String, Integer> stok = new HashMap<>();
stok.put("Pensil", 120);
stok.put("Buku Tulis", 45);
stok.put("Penghapus", 30);
System.out.println("get(Pensil) : " + stok.get("Pensil"));
System.out.println("get(Penggaris) : " + stok.get("Penggaris"));
System.out.println("containsKey(Buku Tulis) : " + stok.containsKey("Buku Tulis"));
System.out.println("containsValue(45) : " + stok.containsValue(45));
stok.put("Pensil", 100);
System.out.println("Pensil setelah put ulang : " + stok.get("Pensil"));
stok.remove("Penghapus");
System.out.println("size() setelah remove : " + stok.size());
System.out.println("keySet() : " + stok.keySet());
System.out.println("values() : " + stok.values());
System.out.println("entrySet():");
for (Map.Entry<String, Integer> entri : stok.entrySet()) {
System.out.println(" " + entri.getKey() + " -> " + entri.getValue());
}
stok.forEach((barang, jumlah) ->
System.out.println(" forEach: " + barang + " berjumlah " + jumlah));
}
}Output yang Dihasilkan:
get(Pensil) : 120
get(Penggaris) : null
containsKey(Buku Tulis) : true
containsValue(45) : true
Pensil setelah put ulang : 100
size() setelah remove : 2
keySet() : [Pensil, Buku Tulis]
values() : [100, 45]
entrySet():
Pensil -> 100
Buku Tulis -> 45
forEach: Pensil berjumlah 100
forEach: Buku Tulis berjumlah 45Mari kita bedah baris-baris pentingnya:
- Baris 5-9 (tiga
putpertama): tiga pasangan masuk;Pensil,Buku Tulis, danPenghapusmenjadi key masing-masing. PemilihanHashMapsebagai implementasi hanya untuk kelangsungan contoh — kontrak yang didemonstrasikan berlaku untuk semuaMap. - Baris 11-12 (
get): pencarian mengembalikan value (120) untuk key yang ada dannulluntuk key yang tidak ada — bentuk umum sinyal “tidak ditemukan” padaMap. - Baris 14-15 (
containsKey/containsValue): keanggotaan key dan keberadaan value adalah dua pertanyaan berbeda;containsValue(45)benar karenaBuku Tulisbernilai45. - Baris 17-18 (
putulang): keyPensilsudah terpasang, jadi100menggantikan120— jumlah pasangan tetap tiga, bukan empat. - Baris 20-21 (
remove+size): penghapusan berdasarkan key;size()turun menjadi2.
Tiga Pandangan Isi Map #
Karena Map bukan Collection, iterasi dilakukan lewat tiga pandangan yang semuanya adalah Collection:
| Pandangan | Tipe elemen | Kegunaan |
|---|---|---|
keySet() | Set<K> | mengiterasi seluruh key |
values() | Collection<V> | mengiterasi seluruh value |
entrySet() | Set<Map.Entry<K,V>> | mengiterasi pasangan lengkap |
Pandangan entrySet() adalah yang paling kaya: setiap elemennya bertipe Map.Entry — objek kecil berisi getKey() dan getValue() sehingga kita membaca pasangan lengkap dalam satu putaran loop. forEach di akhir contoh memakai bentuk lambda (barang, jumlah) — method tersebut menerima BiConsumer yang menerima key dan value secara bersamaan, versi ringkas dari iterasi entrySet().
Pola Hitung dengan Method Modern #
Kasus klasis pemakaian Map adalah menghitung frekuensi kemunculan tiap kata. Java modern menyediakan empat method yang membuat pola ini ringkas. Program berikut membandingkan dua cara menghitung, lalu membangun struktur kelompok kata:
import java.util.*;
public class HitungKata {
public static void main(String[] args) {
String teks = "belajar java setiap hari belajar java coding setiap pagi";
// Versi 1: getOrDefault mengembalikan nilai lama, atau 0 jika key belum ada.
Map<String, Integer> hitungan = new HashMap<>();
for (String kata : teks.split(" ")) {
hitungan.put(kata, hitungan.getOrDefault(kata, 0) + 1);
}
System.out.println("getOrDefault : " + hitungan);
// Versi 2: merge memasang nilai baru lalu menggabungkannya dengan nilai lama.
Map<String, Integer> hitunganMerge = new HashMap<>();
for (String kata : teks.split(" ")) {
hitunganMerge.merge(kata, 1, Integer::sum);
}
System.out.println("merge : " + hitunganMerge);
// putIfAbsent hanya menulis jika key belum terpasang.
hitunganMerge.putIfAbsent("algoritma", 1);
hitunganMerge.putIfAbsent("java", 99);
System.out.println("putIfAbsent : algoritma=" + hitunganMerge.get("algoritma")
+ ", java=" + hitunganMerge.get("java"));
// computeIfAbsent menyiapkan wadah kosong sekali, lalu wadah itu diisi berulang.
Map<Integer, List<String>> perPanjang = new HashMap<>();
for (String kata : teks.split(" ")) {
perPanjang.computeIfAbsent(kata.length(), k -> new ArrayList<>()).add(kata);
}
System.out.println("Kelompok panjang kata:");
perPanjang.forEach((panjang, daftar) ->
System.out.println(" " + panjang + " huruf : " + daftar));
}
}Output yang Dihasilkan:
getOrDefault : {hari=1, coding=1, java=2, setiap=2, pagi=1, belajar=2}
merge : {hari=1, coding=1, java=2, setiap=2, pagi=1, belajar=2}
putIfAbsent : algoritma=1, java=2
Kelompok panjang kata:
4 huruf : [java, hari, java, pagi]
6 huruf : [setiap, coding, setiap]
7 huruf : [belajar, belajar]Poin bedahnya:
- Baris 8-10 (
getOrDefault): saat kata pertama kali muncul,getOrDefault(kata, 0)mengembalikan0, lalu+ 1menghasilkan1; kemunculan berikutnya membaca nilai lama dan menaikkannya. Pola baca-naikkan-tulis ini adalah idiom klasis sebelum Java 8. - Baris 14-16 (
merge): satu baris menggantikan tiga langkah —mergememasang1jika key belum ada, atau memanggilInteger::sumuntuk menjumlahkan nilai lama dengan1. Methodmergejuga menghapus entry jika hasil penggabungannull, perilaku yang berguna saat menghitung selisih stok. - Baris 19-21 (
putIfAbsent): key baru (algoritma) terpasang dengan nilai1, sedangkan key lama (java) tetap bernilai2— penulisan hanya terjadi ketika key belum ada, kebalikan dariputyang selalu menimpa. - Baris 25-26 (
computeIfAbsent): lambdak -> new ArrayList<>()hanya dijalankan sekali per key; setelah list tercipta, pemanggilan berikutnya menerima list yang sama sehinggaaddmenumpuk kata ke kelompoknya. Pola ini adalah cara standar membangun multimap (satu key, banyak value) tanpa memeriksanullmanual.
Dengan kontrak Map di tangan, pertanyaan berikutnya menyasar mesin di baliknya: bagaimana get bisa begitu cepat meski map berisi jutaan pasangan? Jawabannya adalah hashing — dan HashMap adalah implementasi yang paling banyak dipakai di seluruh ekosistem Java. Chapter berikutnya membedah bucket, collision, load factor, dan kontrak equals/hashCode yang membuat semuanya bekerja.
Referensi #
- Java API Specification: java.util.Map
- Java API Specification: java.util.Map.Entry
- Dev.java: The Java Collections Framework
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
HitungKata.java
Unduh berkasimport java.util.*;
public class HitungKata {
public static void main(String[] args) {
String teks = "belajar java setiap hari belajar java coding setiap pagi";
// Versi 1: getOrDefault mengembalikan nilai lama, atau 0 jika key belum ada.
Map<String, Integer> hitungan = new HashMap<>();
for (String kata : teks.split(" ")) {
hitungan.put(kata, hitungan.getOrDefault(kata, 0) + 1);
}
System.out.println("getOrDefault : " + hitungan);
// Versi 2: merge memasang nilai baru lalu menggabungkannya dengan nilai lama.
Map<String, Integer> hitunganMerge = new HashMap<>();
for (String kata : teks.split(" ")) {
hitunganMerge.merge(kata, 1, Integer::sum);
}
System.out.println("merge : " + hitunganMerge);
// putIfAbsent hanya menulis jika key belum terpasang.
hitunganMerge.putIfAbsent("algoritma", 1);
hitunganMerge.putIfAbsent("java", 99);
System.out.println("putIfAbsent : algoritma=" + hitunganMerge.get("algoritma")
+ ", java=" + hitunganMerge.get("java"));
// computeIfAbsent menyiapkan wadah kosong sekali, lalu wadah itu diisi berulang.
Map<Integer, List<String>> perPanjang = new HashMap<>();
for (String kata : teks.split(" ")) {
perPanjang.computeIfAbsent(kata.length(), k -> new ArrayList<>()).add(kata);
}
System.out.println("Kelompok panjang kata:");
perPanjang.forEach((panjang, daftar) ->
System.out.println(" " + panjang + " huruf : " + daftar));
}
}
StokToko.java
Unduh berkasimport java.util.*;
public class StokToko {
public static void main(String[] args) {
Map<String, Integer> stok = new HashMap<>();
stok.put("Pensil", 120);
stok.put("Buku Tulis", 45);
stok.put("Penghapus", 30);
System.out.println("get(Pensil) : " + stok.get("Pensil"));
System.out.println("get(Penggaris) : " + stok.get("Penggaris"));
System.out.println("containsKey(Buku Tulis) : " + stok.containsKey("Buku Tulis"));
System.out.println("containsValue(45) : " + stok.containsValue(45));
stok.put("Pensil", 100);
System.out.println("Pensil setelah put ulang : " + stok.get("Pensil"));
stok.remove("Penghapus");
System.out.println("size() setelah remove : " + stok.size());
System.out.println("keySet() : " + stok.keySet());
System.out.println("values() : " + stok.values());
System.out.println("entrySet():");
for (Map.Entry<String, Integer> entri : stok.entrySet()) {
System.out.println(" " + entri.getKey() + " -> " + entri.getValue());
}
stok.forEach((barang, jumlah) ->
System.out.println(" forEach: " + barang + " berjumlah " + jumlah));
}
}