Interface Map.Entry
A map entry (key-value pair). The Entry may be unmodifiable, or the value may be modifiable if the optional setValue method is implemented. The Entry may be independent of any map, or it may represent an entry of the entry-set view of a map.
Instances of the Map.Entry interface may be obtained by iterating the entry-set view of a map. These instances maintain a connection to the original, backing map. This connection to the backing map is valid only for the duration of iteration over the entry-set view. During iteration of the entry-set view, if supported by the backing map, a change to a Map.Entry ‘s value via the setValue method will be visible in the backing map. The behavior of such a Map.Entry instance is undefined outside of iteration of the map’s entry-set view. It is also undefined if the backing map has been modified after the Map.Entry was returned by the iterator, except through the Map.Entry.setValue method. In particular, a change to the value of a mapping in the backing map might or might not be visible in the corresponding Map.Entry element of the entry-set view.
API Note: It is possible to create a Map.Entry instance that is disconnected from a backing map by using the copyOf method. For example, the following creates a snapshot of a map’s entries that is guaranteed not to change even if the original map is modified:
var entries = map.entrySet().stream().map(Map.Entry::copyOf).toList()
- Использование Java-класса Map.Entry
- 2. Оптимизация итерации карты
- 2.1. Использование Map.keySet
- 2.2. Использование Map.entrySet вместо этого
- 3. Работа с кортежами
- 3.1. Создание кортежа
- 3.2. Создание упорядоченного списка кортежей
- 3.3. Сравнение с картой
- 3.4. Списки объектов входа
- 4. Вывод
- Ответы на самые популярные вопросы об интерфейсе Map
- 0. Как перебрать все значения Map
- 1. Как конвертировать Map в List
- 2. Как отсортировать ключи мапы
- 3. Как отсортировать значения мапы
- 4. В чем разница между HashMap, TreeMap, и Hashtable
- 5. Как создать двунаправленную мапу
- 6. Как создать пустую Map
Использование Java-класса Map.Entry
Мы часто используем карты для хранения набора пар ключ-значение. Затем, в какой-то момент, нам часто нужно перебирать их .
В этом руководстве мы сравним различные методы итерации карты, выделив, когда может быть полезно использовать Map.Entry . Затем мы узнаем, как можно использовать Map.Entry для создания кортежа. Наконец, мы создадим упорядоченный список кортежей.
2. Оптимизация итерации карты
Предположим, что у нас есть карта названий книг с именем автора в качестве ключа:
MapString, String> map = new HashMap>(); map.put("Robert C. Martin", "Clean Code"); map.put("Joshua Bloch", "Effective Java");
Давайте сравним два метода получения всех ключей и значений из нашей карты.
2.1. Использование Map.keySet
Во-первых, рассмотрите следующее:
for (String key : bookMap.keySet()) System.out.println("key: " + key + " value: " + bookMap.get(key)); >
Здесь цикл перебирает набор ключей . Для каждого ключа мы получаем соответствующее значение с помощью Map.get . Хотя это очевидный способ использовать все записи на карте, для каждой записи требуется две операции — одна для получения следующего ключа и одна для поиска значения с помощью get .
Если нам нужны только ключи на карте, keySet — хороший вариант. Однако есть более быстрый способ получить как ключи, так и значения.
2.2. Использование Map.entrySet вместо этого
Давайте перепишем нашу итерацию, чтобы использовать entrySet :
for (Map.EntryString, String> book: bookMap.entrySet()) System.out.println("key: " + book.getKey() + " value: " + book.getValue()); >
В этом примере наш цикл проходит по коллекции объектов Map.Entry . Поскольку Map.Entry хранит и ключ, и значение вместе в одном классе, мы получаем их оба в одной операции .
Те же правила применяются к использованию потоковых операций Java 8 . Потоковая передача через entrySet и работа с объектами Entry более эффективны и могут потребовать меньше кода.
3. Работа с кортежами
Кортеж — это структура данных с фиксированным количеством и порядком элементов. Мы можем думать о Map.Entry как о кортеже, который хранит два элемента — ключ и значение. Однако, поскольку Map.Entry — это интерфейс, нам требуется класс реализации. В этом разделе мы рассмотрим одну реализацию, предоставляемую JDK: AbstractMap.SimpleEntry .
3.1. Создание кортежа
Сначала рассмотрим класс Book :
public class Book private String title; private String author; public Book(String title, String author) this.title = title; this.author = author; > ...
Далее создадим кортеж Map.Entry с ISBN в качестве ключа и объектом Book в качестве значения:
Map.EntryString, Book> tuple;
Наконец, давайте создадим экземпляр нашего кортежа с помощью AbstractMap.SimpleEntry :
tuple = new AbstractMap.SimpleEntry>("9780134685991", new Book("Effective Java 3d Edition", "Joshua Bloch"));
3.2. Создание упорядоченного списка кортежей
При работе с кортежами часто полезно иметь их в виде упорядоченного списка.
Во-первых, мы определим наш список кортежей:
ListMap.EntryString, Book>> orderedTuples = new ArrayList>();
Во-вторых, давайте добавим несколько записей в наш список:
orderedTuples.add(new AbstractMap.SimpleEntry>("9780134685991", new Book("Effective Java 3d Edition", "Joshua Bloch"))); orderedTuples.add(new AbstractMap.SimpleEntry>("9780132350884", new Book("Clean Code","Robert C Martin")));
3.3. Сравнение с картой
Чтобы сравнить различия с Map , давайте добавим новую запись с уже существующим ключом:
orderedTuples.add(new AbstractMap.SimpleEntry>("9780132350884", new Book("Clean Code", "Robert C Martin")));
Во-вторых, мы пройдемся по нашему списку, отображая все ключи и значения:
for (Map.EntryString, Book> tuple : orderedTuples) System.out.println("key: " + tuple.getKey() + " value: " + tuple.getValue()); >
Наконец, давайте посмотрим на вывод:
key: 9780134685991 value: Booktitle='Effective Java 3d Edition', author='Joshua Bloch'> key: 9780132350884 value: Booktitle='Clean Code', author='Robert C Martin'> key: 9780132350884 value: Booktitle='Clean Code', author='Robert C Martin'>
Обратите внимание, что у нас могут быть повторяющиеся ключи, в отличие от базовой карты , где каждый ключ должен быть уникальным. Это связано с тем, что мы использовали реализацию List для хранения наших объектов SimpleEntry , что означает, что все объекты независимы друг от друга.
3.4. Списки объектов входа
Следует отметить, что Entry не предназначен для использования в качестве универсального кортежа. Классы библиотеки часто предоставляют для этой цели универсальный « класс Pair .
Однако мы можем обнаружить, что нам нужно временно работать со списками записей при подготовке данных для Карты или извлечении данных из нее.
4. Вывод
В этой статье мы рассмотрели Map.entrySet как альтернативу перебору ключей карты.
Затем мы рассмотрели, как Map.Entry можно использовать в качестве кортежа.
Наконец, мы создали список упорядоченных кортежей, сравнивая различия с базовой картой .
Как всегда, код примера доступен на GitHub .
Ответы на самые популярные вопросы об интерфейсе Map
Привет! Сегодня мы дадим ответы на самые распространенные вопросы о Map, но для начала давай вспомним, что это такое. Map — это структура данных, которая содержит набор пар “ключ-значение”. По своей структуре данных напоминает словарь, поэтому ее часто так и называют. В то же время, Map является интерфейсом, и в стандартном jdk содержит основные реализации: Hashmap, LinkedHashMap, Hashtable, TreeMap. Самая используемая реализация — Hashmap, поэтому и будем ее использовать в наших примерах. Вот так выглядит стандартное создание и заполнение мапы:
Map 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 entry: map.entrySet()) < // get key Integer key = entry.getKey(); // get value String value = entry.getValue(); >Или используя итератор: Iterator itr = map.entrySet().iterator(); while(itr.hasNext()) < Map.Entryentry = itr.next(); // get key Integer key = entry.getKey(); // get value String value = entry.getValue(); >
1. Как конвертировать Map в List
- keySet() — возвращает множество(Set) ключей;
- values() — возвращает коллекцию(Collection) значений;
- entrySet() — возвращает множество(Set) наборов “ключ-значение”.
// key list List keyList = new ArrayList<>(map.keySet()); // value list List valueList = new ArrayList<>(map.values()); // key-value list List> entryList = new ArrayList<>(map.entrySet());
2. Как отсортировать ключи мапы
- Поместить Map.Entry в список и отсортировать его, используя Comparator. В компараторе будем сравнивать исключительно ключи пар:
List> list = new ArrayList(map.entrySet()); Collections.sort(list, new Comparator>() < @Override public int compare(Map.Entryo1, Map.Entry o2) < return o1.getKey() - o2.getKey(); >>);Collections.sort(list, Comparator.comparingInt(Map.Entry::getKey));
SortedMap sortedMap = new TreeMap<>(new Comparator() < @Override public int compare(Integer o1, Integer o2) < return o1 - o2; >>);
SortedMap sortedMap = new TreeMap<>(Comparator.comparingInt(o -> o));
3. Как отсортировать значения мапы
Здесь стоит использовать подход, аналогичный первому для ключей — получать список значений и сортировать их в списке:
List > valuesList = new ArrayList(map.entrySet()); Collections.sort(list, new Comparator>() < @Override public int compare(Map.Entryo1, Map.Entry o2) < return o1.getValue().compareTo(o2.getValue()); >>);
Collections.sort(list, Comparator.comparing(Map.Entry::getValue));
4. В чем разница между HashMap, TreeMap, и Hashtable
- Порядок элементов. 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 emptyMap = new HashMap<>();
Map emptyMap = Collections.emptyMap();