Java HashMap

Look values up by key with HashMap, keep unique items with HashSet, and choose the right collection.

Lesson 48 of 127Intermediate18 min read

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

Java
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.2
  • Map<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, or null if the key isn't there.
  • Keys are unique; values can repeat.

Useful map methods

MethodWhat 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

Java
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:

Java
Set<String> tags = new HashSet<>();
tags.add("java");
tags.add("java");     // ignored, already there
tags.contains("java"); // true, and very fast

add() 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:

Java
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)));   // true

Never 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.
  • put adds or replaces, get reads, getOrDefault reads safely, remove deletes.
  • Loop with entrySet(); HashMap has no reliable order.
  • LinkedHashMap keeps insertion order and TreeMap sorts by key.
  • HashSet stores unique values with fast contains checks.

Java HashMap Examples

Each example shows the code, the output it produces and what each part does.

Example 1

A product price list

Java
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);
    }
}
Output
{Backpack=34.99, Notebook=3.5, Pen=1.1}
Lamp: 0.0
Has notebook? true
Total of one each: 39.59
Line-by-line explanation
  1. Line 6A TreeMap keeps its keys sorted, so the output is predictable.
  2. Line 10Putting an existing key replaces its value: the pen is now 1.10.
  3. Line 13getOrDefault avoids a null for the missing key.
  4. Line 16values() loops over just the prices.
Example 2

Counting words

Java
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());
            }
        }
    }
}
Output
the: 3
and: 2
Line-by-line explanation
  1. Line 7LinkedHashMap remembers the order words were first seen.
  2. Line 10merge puts 1 for a new word, or adds 1 to the existing count.
  3. Lines 13 to 17Loop over the entries and print only repeated words.
Example 3

Finding duplicates with a HashSet

Java
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);
    }
}
Output
Unique: 3
Duplicates: [ana@x.com, ben@x.com]
Line-by-line explanation
  1. Line 10add returns false when the email is already in the set.
  2. Line 8A TreeSet keeps the duplicates sorted for tidy output.

Common Java HashMap Mistakes

Unboxing a missing value

Don't
Map<String, Integer> stock = new HashMap<>();
int pens = stock.get("Pen");      // NullPointerException
Do
int pens = stock.getOrDefault("Pen", 0);

Expecting a HashMap to keep order

Don't
Map<String, Integer> steps = new HashMap<>();
// put "first", "second", "third"... then print: order may differ
Do
Map<String, Integer> steps = new LinkedHashMap<>();   // keeps insertion order

Using a list for lookups by name

Don't
for (Product p : products) {
    if (p.name().equals("Pen")) return p.price();   // checks every product
}
Do
Map<String, Product> byName = new HashMap<>();   // built once
return byName.get("Pen").price();                 // direct lookup

Java 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.

Fill in the blankseasy

Complete the code that stores and reads a capital city.

Map<String, String> capitals = new HashMap<>();
capitals.("Japan", "Tokyo");
System.out.println(capitals.("Japan"));
Predict the outputeasy

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"));
Predict the outputmedium

What does this print?

Set<Integer> s = new HashSet<>(List.of(3, 1, 3, 2, 1));
System.out.println(s.size() + " " + s.add(2));
Multiple choicemedium

Which map keeps its keys in sorted order?

Multiple choicehard

Which collection best answers "has this username already been taken?" quickly?

Java HashMap Quiz

5 questions to check what you learned.

  1. What does map.get(key) return when the key doesn't exist?

    • null
    • 0
    • An empty string
    • It throws an exception
  2. 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
  3. 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
  4. 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
  5. 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