Course contents

Everyday Map operations: iterate, merge, sort and compare

Everyday HashMap operations: iteration, Map.Entry, merge and compute methods, sorting, comparison, duplicate-value grouping and stream collectors.

PremiumOften askedLesson18 min readCoreReviewed Oct 2026 · Java 21
On this page
  1. Picture it first: choose the method by intent
  2. Iterating a map under the hood
  3. Map.Entry: live view, immutable pair and comparators
  4. Merging maps and updating one key
  5. The compute family, accurately
  6. Sorting a HashMap and taking top N
  7. Comparing maps and finding differences
  8. Working with maps using streams
  9. How to say it in the interview

🧭 What are everyday Map operations?

Everyday Map operations are the moves you use after you already understand how lookup works: iterate entries, update counts, merge results, sort for output and compare two maps. A map acts like a labelled filing cabinet: HashMap gets you to the drawer, but these operations decide how you walk the files, combine folders and produce a report. For example, turning a list of orders into totals by customer is mostly merge, entrySet and a careful collector.

For this lesson, we'll focus on the map operations interviewers expect you to write without searching: efficient iteration, Map.Entry, merging, sorting, comparing, duplicate logical keys, streams and the compute family. We will not repeat the bucket-array internals from How HashMap works; treat that as the engine and this lesson as the driver's manual.

Below the line (out of scope)

The 30-second answer

If you need both key and value, iterate entrySet(), not keySet() plus get(), because each get() repeats a lookup. Use forEach((k, v) -> ...) for clean read-only work, an explicit iterator when you remove while walking, and entrySet().removeIf(...) for filtering entries. Map.Entry is the pair view: Map.entry(k, v) creates an immutable Java 9+ entry, AbstractMap.SimpleEntry is mutable, and entries returned by HashMap.entrySet() let setValue write through to the map. Merge whole maps with putAll when overwrite is fine, merge when you need a rule, and Collectors.toMap with a merge function when a stream may produce duplicate keys. Sort by key with new TreeMap<>(map), sort by value with a stream into LinkedHashMap, and compare maps with equals while remembering that array values compare by identity.

What you’ll learn

  • Choose **entrySet() over keySet() plus get()** when you need both keys and values
  • Use Map.Entry, Map.entry, SimpleEntry and Entry.comparingByKey/Value correctly
  • Merge maps with putAll, merge and Collectors.toMap without falling into the duplicate-key trap
  • Sort map data by key with TreeMap and by value with streams into a LinkedHashMap
  • Compare maps with equals, inspect key differences and handle array values safely
  • Store repeated logical keys with Map<K, List<V>> and computeIfAbsent
  • Know the null-return semantics of compute, computeIfAbsent, computeIfPresent, merge, putIfAbsent and getOrDefault

Interview radar

Asked often: How do you iterate a map efficiently and get both key and value? Core follow-up: What does merge do when the remapping function returns null? Production angle: A Collectors.toMap pipeline passes tests with unique data, then throws IllegalStateException when two orders share a customer id.

01Picture it first: choose the method by intent

Picture a service desk with seven labelled buttons. One button says "read a value", one says "write if missing", one says "combine", one says "remove while walking". The mistake I see in interviews is reaching for put or get first and then patching edge cases around it.

The faster path is intent first, method second. If you can name what you want to happen for absent keys, present keys and null results, Java already has a method for it.

Fig. 1

Decision chart for choosing Map methods: read with getOrDefault, initialize with computeIfAbsent, update present values with computeIfPresent, combine with merge, replace-or-remove with compute, write once with putIfAbsent, and filter with entrySet removeIf

Decision chart for choosing Map methods: read with getOrDefault, initialize with computeIfAbsent, update present values with computeIfPresent, combine with merge, replace-or-remove with compute, write once with putIfAbsent, and filter with entrySet removeIf

Notice the branch that says "returning null removes". That is true for compute, computeIfPresent and the remapping function of merge. It is not true for computeIfAbsent; a null result means "do not store anything".

02Iterating a map under the hood

When you need both parts of each mapping, entrySet() is the default I recommend. It walks each table entry once and hands you a Map.Entry<K,V> that already has the key and value. keySet() plus get(key) is readable for key-only work that grew over time, but if you need the value too, it performs a second lookup per key.

Try it yourself first

Before reading on, choose the better loop for printing employee ids and names. This is the scenario interviewers often ask: "You have a HashMap storing employee IDs as keys and names as values. Which method retrieves both efficiently?"

Map<Integer, String> employees = Map.of(
        101, "Mina",
        102, "Ravi",
        103, "Asha"
);

for (Map.Entry<Integer, String> entry : employees.entrySet()) {
    System.out.println(entry.getKey() + " -> " + entry.getValue());
}

// Usually avoid this when you need values too.
for (Integer id : employees.keySet()) {
    System.out.println(id + " -> " + employees.get(id)); // one extra lookup per key
}

Notice three things:

  • entrySet() is the efficient answer when you need both key and value.
  • keySet() is still fine when you only need keys, for example validating ids.
  • values() is fine when the key is irrelevant, such as summing totals.

For read-only, side-effect-light code, forEach is often the cleanest version:

employees.forEach((id, name) ->
        System.out.println("employee " + id + " is " + name));

That BiConsumer receives key then value. I avoid doing complicated mutation inside it, because control flow gets awkward and exceptions leave you with a half-updated map. If removal is the goal, use the right tool.

Map<String, Integer> stock = new HashMap<>(Map.of(
        "keyboard", 7,
        "mouse", 0,
        "monitor", 3
));

Iterator<Map.Entry<String, Integer>> it = stock.entrySet().iterator();
while (it.hasNext()) {
    Map.Entry<String, Integer> entry = it.next();
    if (entry.getValue() == 0) {
        it.remove();                    // safe structural removal during iteration
    }
}

stock.entrySet().removeIf(entry -> entry.getValue() < 2); // also safe and concise

Calling stock.remove(entry.getKey()) inside an enhanced for loop is the classic ConcurrentModificationException demo. The iterator's own remove coordinates with the iterator's expected modification count. entrySet().removeIf uses the collection view, so it is the version I reach for in production filtering code.

In the real world

I once reviewed a nightly cleanup that did for (String id : map.keySet()) { if (expired) map.remove(id); }. It worked in a tiny manual run because the first expired item ended the test, then failed in production the first night with ConcurrentModificationException. The fix was not clever: iterate entrySet() and call the iterator's remove, or use entrySet().removeIf.

03Map.Entry: live view, immutable pair and comparators

Map.Entry<K,V> is a key-value pair, but not every entry has the same behavior. Entries you get from a mutable map's entrySet() are usually live views of the map. Entries you create with Map.entry(k, v) are immutable value objects, useful for literals and stream setup.

Map<String, Integer> prices = new HashMap<>();
prices.put("standard", 100);
prices.put("express", 250);

Map.Entry<String, Integer> live = prices.entrySet().iterator().next();
live.setValue(live.getValue() + 20);       // writes through to the HashMap

Map.Entry<String, Integer> fixed = Map.entry("priority", 500); // Java 9+
// fixed.setValue(600);                    // UnsupportedOperationException

Map.Entry<String, Integer> editable =
        new AbstractMap.SimpleEntry<>("gift-wrap", 50);
editable.setValue(75);                     // changes the entry object only

Map.entry also rejects null keys and values. SimpleEntry accepts null and is mutable. SimpleImmutableEntry is the older immutable option if you need it on code that predates Java 9.

The comparators are built in:

Premium lesson

Keep reading with the Java Pass

The rest of this lesson is part of Java One-Stop Interview Prep: in-depth explanations, diagrams, model answers and how to say them in the interview.

  • Merging maps and updating one key
  • The compute family, accurately
  • Sorting a HashMap and taking top N
  • Comparing maps and finding differences
  • Working with maps using streams
  • How to say it in the interview

From ₹199 · one-time payment · No auto-renewal

Practise this topicMaps: interview questions & scenarios
Further reading (6)