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
Як згадувалося раніше, існують три основні реалізації інтерфейсу Map. Кожна з них має свої особливості:-
Порядок елементів.
HashMap
іHashtable
не гарантують, що елементи зберігатимуться у порядку додавання. Крім того, вони не гарантують, що порядок елементів не змінюватиметься з часом. У свою чергу,TreeMap
гарантує зберігання елементів у порядку додавання або відповідно до заданого компаратора. -
Допустимі значення.
HashMap
дозволяє мати ключ і значення nullHashTable
- ні. 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.
Що ще почитати: |
---|
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ