00:00

Map Interface in Java – Complete Guide with Examples

Last updated: 10 min read

The Map interface stores data as key–value pairs. Each key is unique and maps to exactly one value, so you can look up a value instantly by its key, like finding a word's meaning in a dictionary or a contact's number by name.

Map lives in java.util and has been part of the Collections Framework since JDK 1.2. Unlike List and Set, it does not extend Collection. This tutorial covers Map's methods, the main implementations, the modern Java 8+ methods, and how to iterate over a map correctly.

1. What Is a Map?

A map links keys to values. Think of a phone's contact list: the name is the key, the number is the value. Names are unique, but two people can share a number.

Java Map key-value pairs example
  • Unique keys: putting a value for an existing key replaces the old value.
  • Duplicate values allowed.
  • Fast lookup by key: O(1) for HashMap, O(log n) for TreeMap.
  • Order depends on the class: none, insertion order, or sorted by key.
  • Collection views: keySet(), values() and entrySet().

2. Hierarchy and Declaration

Map interface hierarchy in Java
java.util.Map
public interface Map<K, V>

K is the key type and V the value type. Sub-interfaces are SortedMap, NavigableMap and, since Java 21, SequencedMap.

3. Basic Operations

put() adds or replaces, get() reads, remove() deletes. put() returns the previous value for the key, or null if there was none.

MapBasics.java
import java.util.HashMap;
import java.util.Map;

public class MapBasics {
    public static void main(String[] args) {
        Map<String, Integer> stock = new HashMap<>();

        stock.put("apple", 50);
        stock.put("mango", 20);
        Integer old = stock.put("apple", 45);        // same key: value replaced

        System.out.println("Stock:              " + stock);
        System.out.println("Old apple value:    " + old);
        System.out.println("get(mango):         " + stock.get("mango"));
        System.out.println("get(kiwi):          " + stock.get("kiwi"));
        System.out.println("getOrDefault(kiwi): " + stock.getOrDefault("kiwi", 0));
        System.out.println("containsKey(apple): " + stock.containsKey("apple"));
        System.out.println("containsValue(20):  " + stock.containsValue(20));

        stock.remove("mango");
        System.out.println("After remove:       " + stock + ", size=" + stock.size());
    }
}
Output
Stock:              {apple=45, mango=20}
Old apple value:    50
get(mango):         20
get(kiwi):          null
getOrDefault(kiwi): 0
containsKey(apple): true
containsValue(20):  true
After remove:       {apple=45}, size=1
Note: get() returns null both when the key is missing and when the key is mapped to null. Use containsKey() or getOrDefault() when the difference matters.

4. Iterating Over a Map

A map is not Iterable itself, but its three views are. Use entrySet() when you need both key and value; it avoids a second lookup per key.

MapIteration.java
import java.util.LinkedHashMap;
import java.util.Map;

public class MapIteration {
    public static void main(String[] args) {
        Map<String, String> capitals = new LinkedHashMap<>();
        capitals.put("India", "New Delhi");
        capitals.put("Japan", "Tokyo");
        capitals.put("Kenya", "Nairobi");

        // 1. entrySet(): key and value together (most common)
        for (Map.Entry<String, String> e : capitals.entrySet()) {
            System.out.println(e.getKey() + " -> " + e.getValue());
        }

        // 2. keySet() and values()
        System.out.println("Keys:   " + capitals.keySet());
        System.out.println("Values: " + capitals.values());

        // 3. forEach with a lambda
        capitals.forEach((country, city) -> System.out.print(city.charAt(0) + " "));
        System.out.println();
    }
}
Output
India -> New Delhi
Japan -> Tokyo
Kenya -> Nairobi
Keys:   [India, Japan, Kenya]
Values: [New Delhi, Tokyo, Nairobi]
N T N
ViewTypeUse it to…
keySet()Set<K>Loop over keys, or remove entries by key.
values()Collection<V>Loop over values (may contain duplicates).
entrySet()Set<Map.Entry<K, V>>Loop over key–value pairs; change values with entry.setValue().

The views are live: removing from them removes entries from the map.

5. Map Implementations

MapImplementations.java
import java.util.*;

public class MapImplementations {
    public static void main(String[] args) {
        String[] keys = {"pear", "apple", "fig", "banana"};

        Map<String, Integer> hash = new HashMap<>();
        Map<String, Integer> linked = new LinkedHashMap<>();
        Map<String, Integer> tree = new TreeMap<>();
        for (String k : keys) {
            hash.put(k, k.length());
            linked.put(k, k.length());
            tree.put(k, k.length());
        }
        System.out.println("HashMap:       " + hash + "   (no guaranteed order)");
        System.out.println("LinkedHashMap: " + linked + "   (insertion order)");
        System.out.println("TreeMap:       " + tree + "   (sorted by key)");
    }
}
Output
HashMap:       {banana=6, apple=5, pear=4, fig=3}   (no guaranteed order)
LinkedHashMap: {pear=4, apple=5, fig=3, banana=6}   (insertion order)
TreeMap:       {apple=5, banana=6, fig=3, pear=4}   (sorted by key)
ClassOrderget / putnull keys / valuesThread-safe
HashMapNoneO(1)One null key, null valuesNo
LinkedHashMapInsertion (or access)O(1)One null key, null valuesNo
TreeMapSorted by keyO(log n)No null key; null valuesNo
HashtableNoneO(1)No nullsYes (legacy)
ConcurrentHashMapNoneO(1)No nullsYes
WeakHashMapNoneO(1)One null key, null valuesNo
IdentityHashMapNoneO(1)One null key, null valuesNo
EnumMapEnum orderO(1), very fastNo null keyNo

6. Java 8+ Methods: merge, compute and More

Java 8 added default methods that replace common "check, then put" code with one call.

MapJava8Methods.java
import java.util.Map;
import java.util.TreeMap;

public class MapJava8Methods {
    public static void main(String[] args) {
        Map<String, Integer> votes = new TreeMap<>();

        // merge(): add 1, or start at 1 if the key is new
        for (String v : new String[] {"red", "blue", "red", "green", "red", "blue"}) {
            votes.merge(v, 1, Integer::sum);
        }
        System.out.println("merge counts:      " + votes);

        votes.putIfAbsent("yellow", 0);          // only if missing
        votes.putIfAbsent("red", 100);           // ignored: red exists
        System.out.println("putIfAbsent:       " + votes);

        votes.computeIfPresent("blue", (k, v) -> v * 10);
        votes.compute("green", (k, v) -> v == null ? 1 : v + 5);
        System.out.println("compute*:          " + votes);

        votes.replaceAll((k, v) -> v + 1);
        System.out.println("replaceAll(+1):    " + votes);

        votes.entrySet().removeIf(e -> e.getValue() < 2);
        System.out.println("removeIf(<2):      " + votes);
    }
}
Output
merge counts:      {blue=2, green=1, red=3}
putIfAbsent:       {blue=2, green=1, red=3, yellow=0}
compute*:          {blue=20, green=6, red=3, yellow=0}
replaceAll(+1):    {blue=21, green=7, red=4, yellow=1}
removeIf(<2):      {blue=21, green=7, red=4}
MethodWhat it does
getOrDefault(k, def)Value for k, or def if absent.
putIfAbsent(k, v)Puts only if k has no value.
merge(k, v, fn)Puts v if absent; otherwise combines old and new with fn. Ideal for counting.
computeIfAbsent(k, fn)Creates a value with fn if absent and returns the value. Ideal for grouping.
computeIfPresent(k, fn)Updates the value only if present.
compute(k, fn)Calculates a new value from the key and the old value (which may be null).
replaceAll(fn)Replaces every value.
forEach((k, v) -> ...)Runs an action for each entry.

If a function passed to merge or one of the compute methods returns null, the entry is removed.

7. Grouping Values with computeIfAbsent()

A very common pattern is a map from a key to a list of values. computeIfAbsent() creates the list the first time a key appears:

GroupWithMap.java
import java.util.*;

public class GroupWithMap {
    public static void main(String[] args) {
        List<String> words = List.of("ant", "bee", "cat", "bear", "cow", "ape", "bull");

        // Group words by first letter: computeIfAbsent creates the list on first use
        Map<Character, List<String>> byLetter = new TreeMap<>();
        for (String w : words) {
            byLetter.computeIfAbsent(w.charAt(0), k -> new ArrayList<>()).add(w);
        }
        System.out.println(byLetter);
    }
}
Output
{a=[ant, ape], b=[bee, bear, bull], c=[cat, cow]}

8. Immutable Maps: Map.of() and Map.ofEntries()

Java 9 added factory methods for small fixed maps. They reject null keys and values, reject duplicate keys, and cannot be changed.

ImmutableMaps.java
import java.util.Map;
import java.util.TreeMap;

public class ImmutableMaps {
    public static void main(String[] args) {
        Map<String, Integer> codes = Map.of("IN", 91, "US", 1, "UK", 44);
        System.out.println("Sorted view: " + new TreeMap<>(codes));

        Map<String, String> big = Map.ofEntries(
                Map.entry("GET", "read"),
                Map.entry("POST", "create"),
                Map.entry("DELETE", "remove"));
        System.out.println("POST means " + big.get("POST"));

        try {
            codes.put("FR", 33);
        } catch (UnsupportedOperationException e) {
            System.out.println("Map.of() is unmodifiable");
        }
        try {
            Map.of("A", 1, "A", 2);
        } catch (IllegalArgumentException e) {
            System.out.println("Duplicate key rejected: " + e.getMessage());
        }
    }
}
Output
Sorted view: {IN=91, UK=44, US=1}
POST means create
Map.of() is unmodifiable
Duplicate key rejected: duplicate key: A

Map.of() accepts up to 10 key–value pairs; use Map.ofEntries() for more. Map.copyOf(map) (Java 10) makes an immutable copy of an existing map. The iteration order of these maps is unspecified, which is why the example wraps one in a TreeMap for display.

9. Core Methods of the Map Interface

MethodDescription
V put(K key, V value)Adds or replaces; returns the old value or null.
void putAll(Map m)Copies all entries from another map.
V get(Object key)Value for the key, or null.
V remove(Object key)Removes the entry; returns its value or null.
boolean remove(key, value)Removes only if the key maps to that value.
V replace(key, value), replace(key, old, new)Replace only if present (or if it has the expected value).
boolean containsKey(key), containsValue(value)Check for a key (fast) or a value (slow, O(n)).
int size(), boolean isEmpty(), void clear()Count, check and empty.
keySet(), values(), entrySet()Live views of keys, values and entries.
Map.entry(k, v)Creates an immutable entry (Java 9).

10. Choosing Good Keys

  • Keys of hash-based maps must implement equals() and hashCode() consistently.
  • Keys of a TreeMap must be Comparable, or you must pass a Comparator.
  • Use immutable keys such as String, Integer, enums or records. Changing a key's fields after putting it in a map makes the entry impossible to find.

11. Which Map Should You Use?

  • HashMap: the default for fast key lookups.
  • LinkedHashMap: predictable insertion order, or an LRU cache with access order.
  • TreeMap: keys sorted, or nearest-key and range queries.
  • ConcurrentHashMap: a map shared between threads.
  • EnumMap: keys are enum constants.
  • Map.of(): small constant lookup tables.

12. Summary

  • Map stores unique keys, each mapped to one value; it does not extend Collection.
  • Core methods: put, get, remove, containsKey, plus the views keySet, values and entrySet.
  • HashMap is unordered, LinkedHashMap keeps insertion order, TreeMap sorts by key.
  • merge, compute* and getOrDefault make counting and grouping simple.
  • Map.of() and Map.ofEntries() create immutable maps.

Related Tutorials

Reference: Java SE 21 API: java.util.Map