
Map<Integer, String> map = new HashMap<>();
map.put(1, "string 1");
map.put(2, "string 2");
map.put(3, "string 3");
А так — получение значений по ключу:
String string1 = map.get(1);
String string2 = map.get(2);
String string3 = map.get(3);
Если все из вышесказанного понятно, приступим к нашим ответам на популярные вопросы!
0. Как перебрать все значения Map
Перебор значений — самая частая операция, которую вы выполняете с мапами. Все пары (ключ-значение) хранятся во внутреннем интерфейсе Map.Entry, а чтобы получить их, нужно вызвать методentrySet()
. Он возвращает множество (Set) пар, которые можно перебрать в цикле:
for(Map.Entry<Integer, String> entry: map.entrySet()) {
// get key
Integer key = entry.getKey();
// get value
String value = entry.getValue();
}
Или используя итератор:
Iterator<Map.Entry<Integer, String>> itr = map.entrySet().iterator();
while(itr.hasNext()) {
Map.Entry<Integer, String> entry = itr.next();
// get key
Integer key = entry.getKey();
// get value
String value = entry.getValue();
}
1. Как конвертировать Map в List
У интерфейса Map существует 3 метода, которые возвращают перечень элементов:- keySet() — возвращает множество(Set) ключей;
- values() — возвращает коллекцию(Collection) значений;
- entrySet() — возвращает множество(Set) наборов “ключ-значение”.
ArrayList
, можно заметить, что существует конструктор с аргументом типа Collection. Так как Set является наследником Collection, результаты всех вышеупомянутых методов можно передать в конструктор класса ArrayList
. Таким образом, мы создадим новые списки и заполним их значениями из Map
:
// key list
List<Integer> keyList = new ArrayList<>(map.keySet());
// value list
List<String> valueList = new ArrayList<>(map.values());
// key-value list
List<Map.Entry<Integer, String>> entryList = new ArrayList<>(map.entrySet());
2. Как отсортировать ключи мапы
Сортировка мап — тоже довольно частая операция в программировании. Сделать это можно несколькими способами:Поместить Map.Entry в список и отсортировать его, используя Comparator.
В компараторе будем сравнивать исключительно ключи пар:
List
> list = new ArrayList(map.entrySet()); Collections.sort(list, new Comparator<Map.Entry<Integer, String>>() { @Override public int compare(Map.Entry<Integer, String> o1, Map.Entry<Integer, String> o2) { return o1.getKey() - o2.getKey(); } }); Если разобрался с лямбдами, эту запись можно существенно сократить:
Collections.sort(list, Comparator.comparingInt(Map.Entry::getKey));
Использовать
SortedMap
, а точнее, ее реализацию —TreeMap
, которая в конструкторе принимает Comparator. Данный компаратор будет применяться к ключам мапы, поэтому ключами должны быть классы, реализующие интерфейсComparable
:SortedMap<Integer, String> sortedMap = new TreeMap<>(new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o1 - o2; } });
И, конечно, все можно переписать, используя лямбды:
SortedMap<Integer, String> sortedMap = new TreeMap<>(Comparator.comparingInt(o -> o));
В отличие от первого способа, используя SortedMap, мы всегда будем хранить данные в отсортированном виде.
3. Как отсортировать значения мапы
Здесь стоит использовать подход, аналогичный первому для ключей — получать список значений и сортировать их в списке:
List <Map.Entry<Integer, String>> valuesList = new ArrayList(map.entrySet());
Collections.sort(list, new Comparator<Map.Entry<Integer, String>>() {
@Override
public int compare(Map.Entry<Integer, String> o1, Map.Entry<Integer, String> o2) {
return o1.getValue().compareTo(o2.getValue());
}
});
И лямбда для этого выглядит так:
Collections.sort(list, Comparator.comparing(Map.Entry::getValue));
4. В чем разница между HashMap, TreeMap, и Hashtable
Как упоминалось ранее, существуют 3 основные реализации интерфейса Map. У каждой из них есть свои особенности:Порядок элементов.
HashMap
иHashtable
не гарантируют, что элементы будут храниться в порядке добавления. Кроме того, они не гарантируют, что порядок элементов не будет меняться со временем. В свою очередь,TreeMap
гарантирует хранение элементов в порядке добавления или же в соответствии с заданным компаратором.Допустимые значения.
HashMap
позволяет иметь ключ и значение null,HashTable
— нет. TreeMap может использовать значения null только если это позволяет компаратор. Без использования компаратора (при хранении пар в порядке добавления) значение null не допускается.Синхронизация. Только
HashTable
синхронизирована, остальные — нет. Если к мапе не будут обращаться разные потоки, рекомендуется использовать HashMap вместо HashTable.
HashMap | HashTable | TreeMap | |
---|---|---|---|
Упорядоченность элементов | нет | нет | да |
null в качестве значения | да | нет | да/нет |
Потокобезопасность | нет | да | нет |
Алгоритмическая сложность поиска элементов | O(1) | O(1) | O(log n) |
Структура данных под капотом | хэш-таблица | хэш-таблица | красно-чёрное дерево |
5. Как создать двунаправленную мапу
Иногда появляется необходимость использовать структуру данных, в которой и ключи, и значения будут уникальными, то есть мапа будет содержать пары “ключ-ключ”. Такая структура данных позволяет создать "инвертированный просмотр/поиск" по мапе. То есть, мы можем найти ключ по его значению.Эту структуру данных называют двунаправленной мапой, которая, к сожалению, не поддерживается JDK. Но, к счастью, ее реализацию можно найти в библиотеках Apache Common Collections или Guava. Там она называется BidiMap и BiMap соответственно. Эти реализации вводят ограничения на уникальность ключей и значений. Таким образом получаются отношения one-to-one.6. Как создать пустую Map
Создать пустую мапу можно двумя способами:Обычная инициализация объекта:
Map<Integer, String> emptyMap = new HashMap<>();
Создание неизменяемой (immutable) пустой мапы:
Map<Integer, String> emptyMap = Collections.emptyMap();
UnsupportedOperationException
исключение.
В этой статье мы рассмотрели самые частые вопросы, которые могли возникнуть у тебя при использовании интерфейса Map.
Что еще почитать: |
---|
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ