Maps

Map is collection of the key/value pairs. Keys are unique. Several keys may map to the same value.

All maps in Java implement the Map interface. Java has a ready the Map implementations, including concurrent maps.

The Map.Entry interface describes the key/value pair.

The Collections class has the utility methods such creating sorted or unmodifiable maps.

Map<String, String> map = new HashMap<>();

map.put("1", "one");
map.put("2", "two");
map.put("3", "three");

// prints 1 2 3, order may be other
for (String key : map.keySet()) {
    System.out.println(key);
}

// prints one two three, order may be other
for (String val : map.values()) {
    System.out.println(val);
}

// prints strings like "1 - one"
// This code is not optimized
//    for(String key: map.keySet()){
//        System.out.println(key + " - " + map.get(key));
//    }
// better to iterate over entries
for (Map.Entry<String, String> entry : map.entrySet()) {
    System.out.println(entry.getKey() + " - " + entry.getValue());
}

Map interface

method description
clear() Removes all items from map.
compute(key, func) Computes new value for given key. If the function returns null, the mapping is removed.
// appends msg to the current value
map.compute(key, (k, v) -> (v == null) ? msg : v.concat(msg)) 
computeIfAbsent(key, func) Computes value for the specified key, if key does not contained in map. Then put the key/value into map.
computeIfPresent(key, func) Computes new value for the specified key, if key is contained in map. If the function returns null, the mapping is removed.
containsKey(key) Returns true if this map contains a mapping for the specified key.
containsValue(value) Returns true if this map maps one or more keys to the specified value.
entrySet() Returns a set of all entries (key/value pairs) in this map. The set is backed by the map, so changes to the map are reflected in the set, and vice-versa.
forEach(action) Performs the action for each entry in this map.
get(key) Returns the value associated with the given key.
getOrDefault(key, defValue) Returns the value associated with the given key, defaultValue if this map contains no mapping for the key.
isEmpty() Returns true if this map contains no key-value mappings.
keySet() Returns a set of the keys contained in this map.
merge(key, value, func) If the specified key is not already associated with a value or is associated with null, associates it with the given non-null value. Otherwise, replaces the associated value with the results of the given remapping function. If the function returns null, the mapping is removed.
put(key, value) Associates the specified value with the specified key in this map.
putAll(srcMap) Copies all entries from the specified map to this map.
putIfAbsent(key, value) If the specified key is not already associated with a value (or is mapped to null) associates it with the given value and returns null, else returns the current value.
remove(key) Removes the mapping for a key from this map if it is present.
remove(key, value) Removes the entry with the specified key and the specified value.
replace(key, value) Replaces the entry for the specified key only if it is currently mapped to some value.
replace(key, oldValue, newValue) Replaces the entry for the specified key only if currently mapped to the specified value.
replaceAll(func) Replaces each entry's value with the result of invoking the given function on that entry.
size() Returns the number of entries in this map.
values() Returns a collection of the values contained in this map.

SortedMap

The SortedMap interface is extension of Map, that provides sorting entries by keys.

HashMap

This implementation provides all of the optional map operations, and permits null values and the null key. This map is thread unsafe.

How does HashMap work? It has the array of buckets. When user puts a new entry, the HashMap calculates index of bucket. Calculation dependends from the hashCode() method of the key object. Inside bucket entries are stored as linked list. So in the worst case, when the hashCode is bad, the map will work like a LinkedList. Since Java 8, when list too large, list will be transformed to the structure similarly to java.util.TreeMap.

HashMap dynamically resizes. Good practice is to avoid unnecessary resizing, so specify initial capacity and load factor in the constructor.

When two or more threads see the need for resizing the same HashMap, they might end up adding the elements of the old bucket to the new bucket simultaneously. As a result, this might lead to infinite loops.

LinkedHashMap

This map is implemented by doubly-linked buckets. Unlike HashMap, the LinkedHashMap maintains order of keys.

LinkedHashMap has two modes of keys ordering: access-order and insertion-order (default). First mode allows to implement the LRU cache, see example.

TreeMap

A Red-Black tree based NavigableMap implementation. The map is sorted according to the natural ordering of its keys, or by a Comparator provided at map creation time, depending on which constructor is used.

This implementation provides guaranteed log(n) time cost for the containsKey, get, put and remove operations.

TreeMap is useful when the information needs to be sorted and when quick random access is necessary. If random access is not needed then rather use sorted set or list.

WeakHashMap

In this implementation keys are stored as the weak references. When a key is no longer referenced outside of the WeakHashMap, the entry with that key will be garbage collected.

EnumMap

A specialized Map implementation for use with enum type keys. This representation is extremely compact and efficient.

Iterators returned by the collection views are weakly consistent: they will never throw ConcurrentModificationException and they may or may not show the effects of any modifications to the map that occur while the iteration is in progress.

IdentityHashMap

Unlike other maps, this implementation using reference-equality when comparing keys and values.

A typical use of this class is topology-preserving object graph transformations, such as serialization or deep-copying. To perform such a transformation, a program must maintain a "node table" that keeps track of all the object references that have already been processed. The node table must not equate distinct objects even if they happen to be equal. Another typical use of this class is to maintain proxy objects. For example, a debugging facility might wish to maintain a proxy object for each object in the program being debugged.