Step 1 of 5 · Reading · ~3 min
Learn
Collections
HashMap
Suppose you need each candidate's vote count. With a list you would store pairs and scan the whole list for every lookup, which gets slower as the data grows. A hash table jumps from a key straight to its entry in (on average) constant time. By the end of this lesson you can store and look up values by key, count occurrences, and keep your output deterministic even though a HashMap has no order.
HashMap: key to value
import java.util.HashMap;
HashMap<String, Integer> votes = new HashMap<>();
votes.put("ana", 3);
votes.put("raj", 5);
votes.put("ana", 4); // same key: OVERWRITES
System.out.println(votes.get("ana")); // 4
System.out.println(votes.containsKey("li")); // false
System.out.println(votes.size()); // 2
votes.remove("raj");
The type arguments are <key type, value type> and, as with ArrayList, must be object types (Integer, not int). Keys are unique, so put on an existing key replaces its value. get on a missing key returns null, which sets up a classic crash:
int v = votes.get("li"); // NullPointerException: unboxing null into an int
Defend with getOrDefault, which supplies a value for absent keys:
int v = votes.getOrDefault("li", 0); // 0, no null in sight
Counting: the idiom
Counting occurrences is the single most useful map pattern: look up the current count (default 0), add one, store it back.
String[] ballots = {"ana", "raj", "ana", "li", "ana", "raj"};
HashMap<String, Integer> tally = new HashMap<>();
for (String b : ballots) {
tally.put(b, tally.getOrDefault(b, 0) + 1);
}
// ana=3, raj=2, li=1 (a map prints in no promised order)
Each pass finds the key (or its default), adds 1 and writes it back, so the first time a name appears it is stored as 0 + 1.
HashSet: just the keys
When all you need is "have I seen this before?", use a HashSet<T>: same hash machinery, no values.
import java.util.HashSet;
HashSet<String> seen = new HashSet<>();
seen.add("ana"); // true: newly added
seen.add("ana"); // false: already there
System.out.println(seen.size()); // 1
Data attached to each key: HashMap. Only membership or distinctness: HashSet.
No order: do not depend on it
A HashMap iterates in an order that is unspecified and may change as the map grows:
for (String name : tally.keySet()) {
System.out.println(name + " " + tally.get(name));
}
That loop may print the names in any order, so output built this way can differ from the expected text even when the data is right. You have three safe options:
- Walk your original data in its own order and look each item up in the map.
- Use a
LinkedHashMap, which iterates in insertion order. - Use a
TreeMap, which iterates in sorted key order.
Walking the original data is also how you break ties by "first to appear": the first element of the input that achieves the best count wins, as long as you only replace the best on a strictly greater count.
Keys rely on equals and hashCode
Maps and sets decide whether two keys are the same using equals and hashCode. String and the wrapper types implement both correctly, which is why they are the usual key types. A key class you write yourself must override both, or two equal-looking objects will be treated as different keys.
Common mistakes
- Unboxing a missing key.
int x = map.get(k);crashes whenkis absent. UsegetOrDefault. - Printing in map-iteration order and expecting stable output.
ArrayList-style indexing. A map has no positions; you ask by key.- Using a mutable object as a key and changing it after insertion.
Your exercise
Find the most frequent word in a line. Counting is the easy part; the part that needs care is a tie, and your output must not depend on the map's internal order. Think about what you can iterate over to make "earliest wins" true by construction.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…