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.
On this page
- Picture it first: choose the method by intent
- Iterating a map under the hood
- Map.Entry: live view, immutable pair and comparators
- 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
🧭 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)
- Hashing, load factor and tree bins: How HashMap works and Hashing, collisions, treeification and load factor
- Ordered maps and LRU caches: LinkedHashMap and building an LRU cache
- Sorted map navigation: TreeMap and red-black trees
- Shared mutable maps: Hashtable, synchronizedMap and the concurrent maps
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()overkeySet()plusget()** when you need both keys and values - Use
Map.Entry,Map.entry,SimpleEntryandEntry.comparingByKey/Valuecorrectly - Merge maps with
putAll,mergeandCollectors.toMapwithout falling into the duplicate-key trap - Sort map data by key with
TreeMapand by value with streams into aLinkedHashMap - Compare maps with
equals, inspect key differences and handle array values safely - Store repeated logical keys with
Map<K, List<V>>andcomputeIfAbsent - Know the null-return semantics of
compute,computeIfAbsent,computeIfPresent,merge,putIfAbsentandgetOrDefault
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.
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.
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