Java HashMap
A HashMap is Java's most used key-value data structure,
providing O(1) average time for get and put operations. It's similar to Python's
Dictionary or JavaScript's Object/Map.
How HashMap Works
HashMap uses a hash table with bucket-based storage:
- Key's
hashCode()determines which bucket - Entry (key-value pair) is stored in that bucket
- Collisions are handled with linked lists (or trees in Java 8+)
- On retrieval,
equals()finds the exact key
Java 8+ Optimization: When a bucket has more than 8 entries,
the linked list converts to a red-black tree for O(log n) lookup instead of O(n).
Key Characteristics
| Feature | HashMap |
|---|---|
| Key uniqueness | Keys must be unique (duplicates overwrite) |
| Value uniqueness | Values can be duplicated |
| Null keys | One null key allowed |
| Null values | Multiple null values allowed |
| Order | No guaranteed order |
| Thread-safe | No (use ConcurrentHashMap) |
Creating a HashMap
import java.util.HashMap;
import java.util.Map;
// Standard way
Map<String, Integer> ages = new HashMap<>();
// With initial capacity
Map<String, String> bigMap = new HashMap<>(1000);
// With initial capacity and load factor
Map<String, String> map = new HashMap<>(16, 0.75f);
// Java 9+ factory method (immutable)
Map<String, Integer> immutable = Map.of(
"Alice", 30,
"Bob", 25
);
Essential Operations
Map<String, Integer> scores = new HashMap<>();
// Adding entries
scores.put("Alice", 95);
scores.put("Bob", 87);
scores.put("Alice", 98); // Overwrites! Returns old value (95)
// Getting values
Integer aliceScore = scores.get("Alice"); // 98
Integer unknown = scores.get("Unknown"); // null
// Safe get with default
Integer score = scores.getOrDefault("Charlie", 0); // 0
// Check existence
boolean hasAlice = scores.containsKey("Alice"); // true
boolean has95 = scores.containsValue(95); // false (was overwritten)
// Remove
Integer removed = scores.remove("Bob"); // Returns 87
// Size
int size = scores.size();
Output
Click Run to execute your code
Iterating Through HashMap
Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 95);
scores.put("Bob", 87);
scores.put("Charlie", 92);
// 1. Iterate over entries (most common)
for (Map.Entry<String, Integer> entry : scores.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
// 2. Iterate over keys only
for (String name : scores.keySet()) {
System.out.println(name);
}
// 3. Iterate over values only
for (Integer score : scores.values()) {
System.out.println(score);
}
// 4. Java 8+ forEach with lambda
scores.forEach((name, score) ->
System.out.println(name + " scored " + score)
);
Advanced Operations (Java 8+)
Map<String, Integer> wordCount = new HashMap<>();
// Compute if absent (great for counters/caches)
wordCount.computeIfAbsent("hello", k -> 0);
// Merge (perfect for counting)
String[] words = {"apple", "banana", "apple", "cherry", "apple"};
for (String word : words) {
wordCount.merge(word, 1, Integer::sum);
}
// {apple=3, banana=1, cherry=1}
// putIfAbsent (only add if key missing)
wordCount.putIfAbsent("date", 1);
// Replace (only if key exists)
wordCount.replace("apple", 5);
// Conditional replace
wordCount.replace("apple", 5, 10); // Only if value is 5
// Remove only if value matches
wordCount.remove("banana", 1); // Removes banana
// Compute (update based on current value)
wordCount.compute("apple", (k, v) -> v == null ? 1 : v + 1);
Common Patterns
// Pattern 1: Counting frequency
Map<Character, Integer> charCount = new HashMap<>();
for (char c : "hello".toCharArray()) {
charCount.merge(c, 1, Integer::sum);
}
// Pattern 2: Grouping
Map<String, List<String>> byLength = new HashMap<>();
for (String word : Arrays.asList("cat", "dog", "elephant", "ant")) {
byLength.computeIfAbsent(
word.length() > 3 ? "long" : "short",
k -> new ArrayList<>()
).add(word);
}
// Pattern 3: Caching/Memoization
Map<Integer, Long> cache = new HashMap<>();
long fibonacci(int n) {
return cache.computeIfAbsent(n, k ->
k <= 1 ? k : fibonacci(k-1) + fibonacci(k-2)
);
}
When to Use Which Map?
| Map Type | Key Order | Performance | Use When |
|---|---|---|---|
HashMap |
None | O(1) | Best general-purpose choice |
LinkedHashMap |
Insertion order | O(1) | Need predictable iteration |
TreeMap |
Sorted by key | O(log n) | Need sorted keys |
ConcurrentHashMap |
None | O(1) | Multi-threaded access |
Summary
- HashMap provides O(1) performance for get/put operations
- Keys must be unique; values can duplicate
- Use
entrySet()for efficient iteration - Java 8+ methods:
merge(),computeIfAbsent(),forEach() - Not thread-safe - use ConcurrentHashMap for concurrent access
Enjoying these tutorials?