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; put returns 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
  • null keys/values: HashMap allows one null key and null values; TreeMap rejects null keys but allows null values; ConcurrentHashMap rejects both
The modern Map API
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, computeIfAbsent, and merge — what each replaces
// 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);
Iteration and bulk ops
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);
LRU cache in six lines
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;
    }
};
Sources
  • Core Java, Volume I: Fundamentals (13th ed.)Ch. 9.4 — Maps
  • Learning Java (6th ed.)Ch. 7 — Collections
  • Effective Java (3rd ed.)Item 37 (EnumMap)