Lists are great when you find things by position. But often you want to find things by a name or an ID instead: the price of a product called "Pen", the phone number for "Ana", the stock level for product 4. Searching a list for those would mean looping through every item. A map looks them up directly.
A HashMap stores key-value pairs. Each key is unique and points to one value, like a word and its definition in a dictionary. Looking up a value by its key is extremely fast, even with millions of entries, because a HashMap uses the key's hash code to jump straight to the right place.
In this lesson you'll add, read, update and remove entries, loop through a map, count things with a map, and meet HashSet for unique values and TreeMap for sorted keys. Along with ArrayList, these are the collections you'll use most in real Java code.
Creating and using a HashMap
import java.util.HashMap;
import java.util.Map;
Map<String, Double> prices = new HashMap<>();
prices.put("Pen", 1.20);
prices.put("Notebook", 3.50);
double p = prices.get("Pen"); // 1.2Map<KeyType, ValueType>has two generic types: the key's and the value's.put(key, value)adds an entry, or replaces the value if the key already exists.get(key)returns the value, ornullif the key isn't there.- Keys are unique; values can repeat.
Useful map methods
| Method | What it does |
|---|---|
getOrDefault(k, d) | The value for k, or d if k is missing |
containsKey(k) / containsValue(v) | Check whether a key or value exists |
remove(k) | Remove an entry |
size() / isEmpty() | Number of entries / is it empty |
putIfAbsent(k, v) | Add only if k isn't already there |
merge(k, 1, Integer::sum) | Add 1 to k's value, starting from 1 |
keySet() / values() / entrySet() | Views for looping |
getOrDefault is the safe way to read a value that might be missing. Unboxing a null into a primitive, as in int n = map.get("x"); for a missing key, throws a NullPointerException.
Looping through a map
for (Map.Entry<String, Double> e : prices.entrySet()) {
System.out.println(e.getKey() + " costs " + e.getValue());
}entrySet() gives you each key-value pair together, which is the most efficient way to loop. Use keySet() when you only need the keys and values() for just the values.
A HashMap does not keep any particular order, and the order can even change as entries are added. If you need entries in the order they were inserted, use LinkedHashMap. If you need keys sorted, use TreeMap. All three share the same Map methods, so switching is a one-word change.
HashSet: unique values
A Set stores values with no duplicates and no positions:
Set<String> tags = new HashSet<>();
tags.add("java");
tags.add("java"); // ignored, already there
tags.contains("java"); // true, and very fastadd() returns false when the value was already present, which is handy for spotting duplicates. Sets are ideal for "have I seen this before?" checks, removing duplicates from a list with new HashSet<>(list), and comparing groups with retainAll() (intersection) and addAll() (union).
Keys need equals and hashCode
A HashMap finds an entry in two steps. First it calls the key's hashCode() to decide which internal bucket to look in, then it calls equals() to find the exact key inside that bucket. That's why lookups stay fast however many entries the map holds.
String, Integer and the other built-in types already implement both methods correctly. For your own classes used as keys, or stored in a HashSet, two objects that are "equal" must also return the same hash code. A plain class doesn't do this by default, so two new Point(1, 2) objects count as different keys. A record generates matching equals and hashCode for you:
record Point(int x, int y) {}
Set<Point> visited = new HashSet<>();
visited.add(new Point(1, 2));
System.out.println(visited.contains(new Point(1, 2))); // trueNever change a key object after putting it in a map: its hash code changes, the map looks in the wrong bucket, and the entry becomes impossible to find. Immutable keys such as strings, numbers and records avoid the problem.
Java HashMap Syntax
Map and Set syntax
import java.util.*;
Map<String, Integer> map = new HashMap<>();
map.put("key", 1);
map.get("key");
map.getOrDefault("other", 0);
map.merge("key", 1, Integer::sum);
for (Map.Entry<String, Integer> e : map.entrySet()) { }
Set<String> set = new HashSet<>();
set.add("x");
set.contains("x");Java HashMap Summary
Map<K, V> map = new HashMap<>();stores unique keys, each with a value.putadds or replaces,getreads,getOrDefaultreads safely,removedeletes.- Loop with
entrySet(); HashMap has no reliable order. LinkedHashMapkeeps insertion order andTreeMapsorts by key.HashSetstores unique values with fastcontainschecks.
Java HashMap Examples
Each example shows the code, the output it produces and what each part does.
A product price list
import java.util.Map;
import java.util.TreeMap;
public class Main {
public static void main(String[] args) {
Map<String, Double> prices = new TreeMap<>();
prices.put("Pen", 1.20);
prices.put("Notebook", 3.50);
prices.put("Backpack", 34.99);
prices.put("Pen", 1.10);
System.out.println(prices);
System.out.println("Lamp: " + prices.getOrDefault("Lamp", 0.0));
System.out.println("Has notebook? " + prices.containsKey("Notebook"));
double total = 0;
for (double p : prices.values()) total += p;
System.out.printf("Total of one each: %.2f%n", total);
}
}{Backpack=34.99, Notebook=3.5, Pen=1.1}
Lamp: 0.0
Has notebook? true
Total of one each: 39.59Line-by-line explanation
- Line 6A TreeMap keeps its keys sorted, so the output is predictable.
- Line 10Putting an existing key replaces its value: the pen is now 1.10.
- Line 13getOrDefault avoids a null for the missing key.
- Line 16values() loops over just the prices.
Counting words
import java.util.LinkedHashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
String text = "the cat and the hat and the bat";
Map<String, Integer> counts = new LinkedHashMap<>();
for (String word : text.split(" ")) {
counts.merge(word, 1, Integer::sum);
}
for (Map.Entry<String, Integer> e : counts.entrySet()) {
if (e.getValue() > 1) {
System.out.println(e.getKey() + ": " + e.getValue());
}
}
}
}the: 3
and: 2Line-by-line explanation
- Line 7LinkedHashMap remembers the order words were first seen.
- Line 10merge puts 1 for a new word, or adds 1 to the existing count.
- Lines 13 to 17Loop over the entries and print only repeated words.
Finding duplicates with a HashSet
import java.util.*;
public class Main {
public static void main(String[] args) {
List<String> emails = List.of("ana@x.com", "ben@x.com", "ana@x.com", "dev@x.com", "ben@x.com");
Set<String> seen = new HashSet<>();
Set<String> duplicates = new TreeSet<>();
for (String e : emails) {
if (!seen.add(e)) {
duplicates.add(e);
}
}
System.out.println("Unique: " + seen.size());
System.out.println("Duplicates: " + duplicates);
}
}Unique: 3
Duplicates: [ana@x.com, ben@x.com]Line-by-line explanation
- Line 10add returns false when the email is already in the set.
- Line 8A TreeSet keeps the duplicates sorted for tidy output.
Common Java HashMap Mistakes
Unboxing a missing value
Map<String, Integer> stock = new HashMap<>();
int pens = stock.get("Pen"); // NullPointerExceptionint pens = stock.getOrDefault("Pen", 0);Expecting a HashMap to keep order
Map<String, Integer> steps = new HashMap<>();
// put "first", "second", "third"... then print: order may differMap<String, Integer> steps = new LinkedHashMap<>(); // keeps insertion orderUsing a list for lookups by name
for (Product p : products) {
if (p.name().equals("Pen")) return p.price(); // checks every product
}Map<String, Product> byName = new HashMap<>(); // built once
return byName.get("Pen").price(); // direct lookupJava HashMap in Real Projects
Maps in real Java code
Web applications keep user sessions in maps keyed by session ID, caches map a request to a stored response, and configuration is read into a Map<String, String>. When a list needs to be grouped, such as orders by customer or students by class, the result is almost always a map of lists.
Java HashMap FAQ
Can a HashMap have null keys or values?
A HashMap allows one null key and any number of null values. A TreeMap rejects null keys because it can't compare them, and maps made with Map.of reject null keys and values. Because get also returns null for a missing key, use containsKey when null values are possible.
Is HashMap thread-safe?
No. Changing a HashMap from several threads at once can corrupt it. Use ConcurrentHashMap for maps shared between threads; it allows safe concurrent reads and updates, and methods like merge and compute update a single entry atomically.
How do I sort a HashMap by its values?
A HashMap itself has no order, so sort its entries into a list or stream: map.entrySet().stream().sorted(Map.Entry.comparingByValue()). Add Comparator.reverseOrder() inside comparingByValue for largest first. Collect the result into a LinkedHashMap if you need a map that keeps that order.
How do I remove entries from a map while looping?
Don't call map.remove inside a for-each loop over the map; that throws a ConcurrentModificationException. Use map.entrySet().removeIf(e -> e.getValue() == 0), or loop with an explicit Iterator and call iterator.remove().
How fast is a HashMap?
get, put, containsKey and remove take roughly constant time on average, written O(1), no matter how many entries there are. A TreeMap takes O(log n) for the same operations in exchange for keeping keys sorted. Searching a list for a key takes O(n), which is why maps are used for lookups.
Java HashMap Exercises
Answer each one and check it instantly. If you get stuck, open the hint before the answer.
Complete the code that stores and reads a capital city.
Map<String, String> capitals = new HashMap<>();
capitals.("Japan", "Tokyo");
System.out.println(capitals.("Japan"));
What does this print?
Map<String, Integer> m = new HashMap<>();
m.put("a", 1);
m.put("a", 5);
System.out.println(m.size() + " " + m.get("a"));
What does this print?
Set<Integer> s = new HashSet<>(List.of(3, 1, 3, 2, 1));
System.out.println(s.size() + " " + s.add(2));
Which map keeps its keys in sorted order?
Which collection best answers "has this username already been taken?" quickly?
Java HashMap Quiz
5 questions to check what you learned.
What does
map.get(key)return when the key doesn't exist?- null
- 0
- An empty string
- It throws an exception
What's the most efficient way to loop over keys and values together?
- keySet() and get() for each key
- values()
- entrySet()
- A normal for loop with an index
Can a HashMap contain the same key twice?
- Yes
- Only for String keys
- Only if the values differ
- No, putting an existing key replaces its value
What does
merge(word, 1, Integer::sum)do?- Removes the word
- Sets the count to 1 for a new word, or adds 1 to an existing count
- Joins two maps
- Sorts the map
When should you use a LinkedHashMap instead of a HashMap?
- When you need entries in the order they were inserted
- When keys must be sorted
- When values are numbers
- When the map is very small