Collections Framework
Maps
Map associates keys with values — the most used data structure in Java after lists. HashMap is the O(1) default; TreeMap keeps keys sorted; LinkedHashMap remembers order and can act as an LRU cache. The modern API (getOrDefault, computeIfAbsent, merge) removes almost every manual null dance.- A key maps to exactly one value;
putreturns the previous value or null getOrDefault,putIfAbsent,computeIfAbsent,merge— learn these four- Iterate
entrySet()when you need both key and value - Keys must be stable: mutating a key in place breaks the map
LinkedHashMap+removeEldestEntry= instant LRU cache- Views:
keySet(),values(),entrySet()write through to the map nullkeys/values:HashMapallows one null key and null values;TreeMaprejects null keys but allows null values;ConcurrentHashMaprejects both
Map<String, Integer> counts = new HashMap<>();
// Counting — three eras:
Integer old = counts.get(word); // 2004
counts.put(word, old == null ? 1 : old + 1);
counts.put(word, counts.getOrDefault(word, 0) + 1); // 2014
counts.merge(word, 1, Integer::sum); // idiomatic now
// Multimap idiom — no null checks:
Map<String, List<Order>> byCustomer = new HashMap<>();
byCustomer.computeIfAbsent(customer, k -> new ArrayList<>()).add(order);computeIfAbsent returns the existing or newly-computed value, making one-line multimaps and caches. merge(key, value, remapper) handles "insert or combine". These also have atomic semantics on ConcurrentHashMap, where they replace lock-protected check-then-act sequences.
// getOrDefault: replaces `map.containsKey(k) ? map.get(k) : fallback`
int priority = priorities.getOrDefault(task, DEFAULT_PRIORITY);
// computeIfAbsent: replaces "check null, create, put, then use" for lazy init / multimaps
List<Order> orders = byCustomer.computeIfAbsent(customer, k -> new ArrayList<>());
orders.add(order);
// merge: replaces "get, null-check, put-or-combine" for counters and accumulators
wordCounts.merge(word, 1, Integer::sum); // insert 1, or add 1 to existing
totals.merge(department, invoice.amount(), BigDecimal::add);for (Map.Entry<String, Integer> e : counts.entrySet()) {
System.out.println(e.getKey() + ": " + e.getValue());
}
counts.forEach((k, v) -> System.out.println(k + ": " + v));
counts.replaceAll((k, v) -> v * 2);Map<K, V> cache = new LinkedHashMap<>(16, 0.75f, true) { // true = access order
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() > MAX_ENTRIES;
}
};