Map. Ассоциативные массивы в Java.

 

Map. Ассоциативные массивы в Java.

Image

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 - обертки
  • 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);
    }
}