Map. Ассоциативные массивы в Java.
Map (ассоциативный массив)
interface Map < K, V >
int size();
boolean isEmpty();
boolean containsKey(Object key);
boolean containsValue(Object value);
V get(Object key);
V put(K key, V value);
V remove(Object key);
void putAll(Map<? extends K, ? extends V> m);
void clear();
Set<K> setKey();
Collections<V> values();
Set<Map.entry<K, V>> entrySet();
V getOrDefault(Object key, V defaultvalue);
V putIfAbsent(K key, V value);
boolean remove(Object key, Object value);
boolean replace(K key, V oldValue, V newValue);
V replace(K key, V value);
Реализации Map
- HashMap - неупорядоченный изменяемый Map общего назначения
- LinkedHashMap - упорядоченный изменяемый Map общего назначения
- TreeMap - сортированный изменяемый Map
- EnumMap - Map, где ключи - элементы Enum
- IdentityHashMap - Map, где ключи сравниваются по == (открытая адресация)
- Collections.singletonMap(k, v) - не изменяемый Map из одного элемента
- Collections.emptyMap() - не изменяемый пустой Map
- Map.of(k1, v1, k2, v2 …); Map.ofEntries(Map.entry(k1, v1), ..) - не изменяемые Map (java 9)
- Collections.unmodifiableMap, synchronizedMap, checkedMap - обертки
NavigableMap< K,V > extends SortedMap< K,V >
lowerKey, lowerEntry, floorKey, floorEntry
higherKey, higherEntry, ceilingKey, ceilingEntry
firstKey, firstEntry, lastKey, lastEntry
pollFirstEntry, pollLastEntry
descendingMap, navigableKeySet, descendingKeySet
subMap, headMap, tailMap
Обход Map в цикле
class Main {
/* Правильный метод */
void iterateOverMap(Map<String, Integer> map) {
for (Map.Entry<String, Integer> entry : map.entrySet()){
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key + " -> " + value);
}
}
/* Не правильный метод (существенно медленнее) */
void iterateOverMap(Map<String, Integer> map) {
for (String key : map.keySet()){
Integer value = map.get(key);
System.out.println(key + " -> " + value);
}
}
/* Обход в функциональном стиле */
void iterateOverMap(Map<String, Integer> map) {
map.forEach((key, value) -> System.out.println(key + " -> " + value));
}
}
Модификация Map при обходе
class Main {
/* !Не правильный метод */
void trimAllValues(Map<String, Integer> map) {
for (String key : map.keySet()) {
String value = map.getKey(key);
map.put(key, value.trim());
}
}
/* Правильный метод */
void trimAllValues(Map<String, Integer> map) {
for (Map.Entry<String, Integer> entry : map.entrySet()){
entry.setValue(entry.getValue.trim());
}
}
/* Лучший метод */
void trimAllValues(Map<String, Integer> map) {
map.replaceAll((key, value) -> value.trim());
}
}
Удаление ненужных значений в Map
class Main {
void removeUnwantedValues(Map<String, Integer> map) {
map.entrySet().removeIf(entry ->
entry.getValue().equals("foo") ||
entry.getValue().equals("bar") ||
entry.getValue().equals("baz"));
}
void removeUnwantedValues(Map<String, Integer> map) {
map.values().removeIf(value ->
value.equals("foo") || value.equals("bar") || value.equals("baz"));
}
private static final List<String> UNWANTED_VALUES = Arrays.asList("foo", "bar", "baz");
void removeUnwantedValues(Map<String, Integer> map) {
map.values().removeAll(UNWANTED_VALUES);
}
}
Multi-Map
class Main {
Map<String, List<String>> multiMap = new HashMap();
void add(String key, String value) {
List<String> list = multiMap.get(key);
if (list == null) {
list = new ArrayList<>();
multiMap.put(key, list);
}
list.add(value);
}
/* >= Java 8*/
void add(String key, String value) {
multiMap.computeIfAbsent(key, k -> new ArrayList<>()).add(value);
}
}
Multi-Set/Bag
class Main {
Map<String, Integer> counts = new HashMap<>();
void add(String key) {
Integer count = counts.get(key);
if (count == null) {
count = 0;
}
counts.put(key, count + 1);
}
void add(String key) {
counts.merge(key, 1, (a, b) -> a + b);
}
}