Java HashMap: Complete Guide With Examples

Java HashMap guide with examples for put, get, merge, compute, iteration, keys, internals and thread safety, plus links to every HashMap how-to.

Decision tree for choosing between HashMap, LinkedHashMap, TreeMap, ConcurrentHashMap and EnumMap based on order, thread safety and key type

A Java HashMap is the general-purpose implementation of the Map interface that stores key-value pairs in a hash table, so it finds the value for a key in constant time on average. Each key appears once, values can repeat, one null key and any number of null values are allowed, and the iteration order is not defined.

We use a HashMap whenever we look things up by a key, for example a user by user name, a price by product code, or a counter by word. The class belongs to the Java Collections framework in the java.util package. The following example shows the everyday operations, with the result of each line as a comment.

Map<String, Integer> scores = new HashMap<>();
Integer added = scores.put("alex", 40);                    // null, new key
Integer replaced = scores.put("alex", 45);                 // 40, old value returned
Integer kept = scores.putIfAbsent("alex", 99);             // 45, existing value stays
Integer alex = scores.get("alex");                         // 45
Integer none = scores.get("sam");                          // null, no such key
Integer orZero = scores.getOrDefault("sam", 0);            // 0
Integer counted = scores.merge("maria", 10, Integer::sum); // 10, inserted
Integer summed = scores.merge("maria", 5, Integer::sum);   // 15, added to the old value
boolean hasAlex = scores.containsKey("alex");              // true
Integer removed = scores.remove("alex");                   // 45
int size = scores.size();                                  // 1

Notice that put() and remove() return the previous value, which tells us whether the key was there. We cover creating and sizing a map, the update methods added in Java 8, keys and their hashCode(), what happens inside the map, thread safety, and how HashMap compares with the other Map classes. The last sections link the detailed articles for each HashMap task.

1. What Is a HashMap in Java?

The HashMap class implements Map<K, V> and extends AbstractMap. Internally, it keeps an array of buckets, and the bucket of each entry comes from the hashCode() of its key, which is why get() and put() do not have to search the whole map. Five properties decide when it fits and when another map is the better choice.

  • Keys are unique. A second put() with an equal key replaces the value, and equality comes from equals() and hashCode().
  • One null key and any number of null values are allowed.
  • The iteration order is not defined and can change when the map grows, so a HashMap is not a SequencedMap.
  • It is not synchronized. Threads that share a HashMap and write to it need a ConcurrentHashMap or another thread-safe map.
  • Its iterators are fail-fast, so changing the map structure during a loop throws ConcurrentModificationException.
Decision tree for choosing between HashMap, LinkedHashMap, TreeMap, ConcurrentHashMap and EnumMap based on order, thread safety and key type
HashMap is the default Map; we move to another implementation only when we need order, sorting, thread safety or enum keys

The decision tree shows the questions that lead away from HashMap. If none of them applies, a HashMap is the fastest and simplest choice.

2. Creating a HashMap

A new HashMap is empty, starts with room for 16 buckets and grows by doubling when it is 75% full. The constructor we pick depends on what we know up front.

Map<String, Integer> empty = new HashMap<>();                          // 16 buckets on the first put
Map<String, Integer> forThousand = HashMap.newHashMap(1_000);          // Java 19+, no resize up to 1,000 entries
Map<String, Integer> filled = new HashMap<>(Map.of("alex", 40, "maria", 70));
Integer maria = filled.get("maria");                                   // 70
Map<String, Integer> copy = new HashMap<>(filled);
Integer old = copy.put("alex", 50);                                    // 40, the original map still has 40
Integer original = filled.get("alex");                                 // 40

Map.of() returns an unmodifiable map, so we pass it to the copy constructor when we want to change the entries later. The copy constructor copies the entries, not the key and value objects, so a mutable value object is shared by both maps. The articles on deep copies and on sizing with newHashMap() and the load factor are listed in section 10.

3. Put, Get and Remove Operations

The basic methods come from the Map interface. Most of them return the previous value or null, so a null result means either that the key was absent or that it was mapped to null.

MethodWhat it doesReturns
put(k, v)Adds or replaces the mappingPrevious value or null
putIfAbsent(k, v)Adds only if the key is absent or mapped to nullExisting value or null
putAll(map)Copies all mappings of another mapNothing
get(k)Reads the valueValue or null
getOrDefault(k, d)Reads the value with a fallbackValue or d
containsKey(k) / containsValue(v)Checks for a key (fast) or a value (scans the map)boolean
remove(k) / remove(k, v)Removes the key, or the key only when it maps to vOld value / boolean
replace(k, v) / replace(k, old, new)Replaces only an existing mappingOld value / boolean
size(), isEmpty(), clear()Counts, checks or empties the mapint, boolean, nothing
Map<String, String> cities = new HashMap<>();
String first = cities.put("lokesh", "Delhi");             // null
String moved = cities.replace("lokesh", "Pune");           // "Delhi"
String nobody = cities.replace("sam", "Rome");             // null, sam was never added
boolean wrong = cities.remove("lokesh", "Delhi");          // false, the value is "Pune"
boolean right = cities.remove("lokesh", "Pune");           // true
String nullKey = cities.put(null, "unknown");              // null, one null key is allowed
String readNull = cities.get(null);                        // "unknown"

When a map can hold null values, get() cannot tell a missing key from a null value, so we check with containsKey(). The method containsValue() walks every entry, which makes it slow on large maps.

4. Updating Values With compute() and merge()

Java 8 added methods to Map that read, change and write a value in one call. They replace the get-check-put pattern, which takes more code and needs its own null check.

MethodRuns the function whenTypical use
merge(k, v, fn)The key exists (absent keys get v)Counters and sums
computeIfAbsent(k, fn)The key is absentCreating a list or cache value on first use
computeIfPresent(k, fn)The key existsUpdating or removing an existing value
compute(k, fn)AlwaysAny update that also handles the absent case
replaceAll(fn)For every entryChanging all values at once

If the function returns null, the entry is removed. A Map<String, List<String>> filled with computeIfAbsent() is the standard way to keep several values per key.

Map<String, Integer> views = new HashMap<>();
Integer v1 = views.merge("home", 1, Integer::sum);                         // 1
Integer v2 = views.merge("home", 1, Integer::sum);                         // 2
Map<String, List<String>> tags = new HashMap<>();
boolean tagged = tags.computeIfAbsent("java", k -> new ArrayList<>()).add("streams");   // true
Integer doubled = views.computeIfPresent("home", (page, n) -> n * 2);     // 4
Integer gone = views.compute("home", (page, n) -> null);                   // null, the entry is removed
boolean hasHome = views.containsKey("home");                               // false

5. Looping Over Keys, Values and Entries

A HashMap offers three views to loop over, keySet(), values() and entrySet(), plus the forEach() method. For keys and values together, we use entrySet() or forEach(), because a keySet() loop that calls get() repeats a lookup for every key.

Map<String, Integer> scores = new HashMap<>(Map.of("alex", 40, "maria", 70));
int total = 0;
for (Map.Entry<String, Integer> entry : scores.entrySet()) {
    total += entry.getValue();
}
int sum = total;                                                          // 110
List<String> sortedNames = scores.keySet().stream().sorted().toList();    // [alex, maria]
boolean removed = scores.values().removeIf(score -> score < 50);          // true

Removing entries through a view, as the last line does, is safe during iteration, whereas map.remove() inside a for-each loop throws ConcurrentModificationException. The iteration article in section 10 compares all ways to loop with a JMH run on JDK 25.

6. Choosing Keys With equals(), hashCode() and Records

A key class must override equals() and hashCode() together, using the same fields, because HashMap picks the bucket with hashCode() and finds the key in the bucket with equals(). Without the overrides, two objects with the same data are different keys. Records generate both methods from their components, which makes a record the simplest key type.

record AccountKey(String bank, int number) {}
Map<AccountKey, Long> balances = new HashMap<>();
Long first = balances.put(new AccountKey("hdfc", 1001), 500L);         // null
Long read = balances.get(new AccountKey("hdfc", 1001));                // 500, an equal record finds the entry

Keys must also stay unchanged while they are in the map. If a field used by hashCode() changes after put(), get() searches a different bucket and returns null, although the entry is still there and still shows up in a loop. Records with immutable fields, String and the wrapper classes avoid that problem.

7. Buckets, Tree Bins and Resizing Inside a HashMap

A HashMap computes the bucket index as (n – 1) & hash, where n is the table length (always a power of two) and hash is the key’s hashCode() with its high bits mixed into the low ones. Keys that share a bucket form a linked list. Since Java 8 (JEP 180), a bucket that gets a 9th node turns into a red-black tree once the table has 64 buckets, so a crowded bucket costs O(log n) instead of O(n).

When the number of entries passes capacity x 0.75, the map doubles the table and moves every entry, which is why a known size passed to HashMap.newHashMap() saves work. The internals article in section 10 walks through put() and get() with the JDK 25 source.

OperationAverageWorst case
get(), put(), remove(), containsKey()O(1)O(log n) for a tree bucket of Comparable keys, O(n) otherwise
containsValue()O(n)O(n)
Iterating all entriesO(capacity + n)O(capacity + n)
A put() that triggers a resizeO(n) for that callO(n)

8. HashMap and Threads

A HashMap is not thread-safe, so two threads that write to the same map can lose updates or leave it in a broken state. Reading from many threads is safe only when no thread writes after the map was safely published, for example a map built once at startup and never changed.

For shared maps that change, we use ConcurrentHashMap, which reads without locks and locks one bucket per write. Collections.synchronizedMap() wraps a HashMap with one lock for all calls. The atomic methods of the concurrent maps are explained in the ConcurrentMap guide.

ConcurrentHashMap<String, Integer> hits = new ConcurrentHashMap<>();
Integer h1 = hits.merge("home", 1, Integer::sum);                     // 1, safe from many threads
Map<String, Integer> fixed = Map.copyOf(Map.of("timeout", 30));
Integer t = fixed.get("timeout");                                     // 30, unmodifiable, safe to share

9. HashMap vs Other Map Implementations

Every Map class in the JDK solves one extra need on top of key lookup. Each alternative in the table links to its own article, and the columns show the need that each one adds.

ClassOrdernull keysThread-safePick it when
HashMapNoneOneNoFast lookups with no other need
LinkedHashMapInsertion or access orderOneNoPredictable order, LRU caches
TreeMapSorted by keyNo (natural order)NoSorted keys, range queries
ConcurrentHashMapNoneNoYesShared, changing maps
EnumMapEnum declaration orderNoNoEnum keys
WeakHashMapNoneOneNoEntries that disappear with their key
IdentityHashMapNoneOneNoKeys compared with ==
HashtableNoneNoYes, one lockLegacy code only

The most common comparison is with the sorted map, which TreeMap vs HashMap covers with performance and memory numbers. A LinkedHashMap and a TreeMap are also SequencedMap instances since Java 21, so they offer firstEntry(), lastEntry() and reversed().

10. Common HashMap Tasks

Most day-to-day HashMap work falls into a few groups of tasks, and each task has a detailed article with tested examples. The first group is about creating, copying and combining maps.

The second group reads and converts the data in a map.

The third group explains how the class behaves under load, and the Java Map series lists every Map article on the site.

11. Blocking Repeated Login Failures With a HashMap

A login service locks an account for a few minutes after five wrong passwords in a row. The failure count per user name is a classic HashMap job, because every login attempt reads and updates one key, and the map never needs an order.

static boolean recordFailure(Map<String, Integer> failures, String user) {
    int count = failures.merge(user, 1, Integer::sum);
    return count >= 5;                                         // true means lock the account
}
Map<String, Integer> failures = new HashMap<>();
boolean locked = false;
for (int i = 0; i < 5; i++) {
    locked = recordFailure(failures, "alex");
}
boolean alexLocked = locked;                                   // true
Integer reset = failures.remove("alex");                       // 5, cleared after a successful login

In a real server, many request threads call recordFailure() at the same time, so the map must be a ConcurrentHashMap. The method signature takes a Map, so the code does not change, and merge() stays atomic on the concurrent map.

12. Java HashMap FAQs

Each answer gives the rule first and names the class to use when HashMap does not fit.

12.1. Can a HashMap have duplicate keys?

No. A key appears once, and a second put() with an equal key replaces the value and returns the old one. Values can repeat freely. To keep several values for one key, we store a collection as the value, for example with computeIfAbsent(key, k -> new ArrayList<>()).add(value).

12.2. Does HashMap allow null keys and values?

Yes. A HashMap allows one null key, which it stores in bucket 0, and any number of null values. ConcurrentHashMap, TreeMap with natural ordering, Hashtable and Map.of() reject null keys.

12.3. Does HashMap keep insertion order?

No. The order depends on the hash codes and the capacity, and it can change after a resize. LinkedHashMap keeps insertion order and TreeMap keeps keys sorted.

Map<String, Integer> ordered = new LinkedHashMap<>();
Integer a = ordered.put("maria", 70);                // null
Integer b = ordered.put("alex", 40);                 // null
String firstKey = ordered.keySet().iterator().next();  // "maria"

12.4. What is the difference between HashMap and Hashtable?

Hashtable is a legacy class from Java 1.0 that synchronizes every method and rejects null keys and values. HashMap is not synchronized and accepts null. For a thread-safe map in new code, we use ConcurrentHashMap instead of Hashtable.

12.5. Is HashMap.get() O(1)?

On average, yes. With a reasonable hashCode(), each bucket holds very few entries. In the worst case, many keys share a bucket, and lookups cost O(log n) for Comparable keys in a tree bucket or O(n) for other keys.

13. Conclusion

A HashMap is the default Map in Java, with average constant-time lookups, unique keys, null support and no defined order. We create it with new HashMap<>(), with HashMap.newHashMap(n) for a known size, or as a mutable copy of Map.of().

For updates, merge() and the compute methods replace get-check-put code, and records make the safest keys because they generate equals() and hashCode() and stay unchanged. When we need order, sorting, enum keys or several threads, we switch to LinkedHashMap, TreeMap, EnumMap or ConcurrentHashMap.

14. References

Happy Learning !!

Source Code on Github

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.