Откройте для себя более безопасную альтернативу сопоставлению ключей с несколькими значениями в Java.
Мне нужна карта с несколькими значениями
В какой-то момент за годы написания кода на Java вам, вероятно, понадобился файл Map<K, Collection<V>>
. Если он вам еще не нужен, дайте ему время… он вам понадобится. Существуют более удобные способы управления Collection
частью Map
с помощью методов, доступных начиная с Java 8. Если вы никогда раньше не использовали computeIfAbsent
, этот метод стоит изучить. Ниже приведен пример создания Map<String, List<String>>
с использованием computeIfAbsent
.
Принцип работы computeIfAbsent
прост. Во-первых, он ищет на карте указанный ключ (например, «A»). Если он не находит значение по ключу, он оценивает указанный Function
и сохраняет результат в файле Map
. Затем он возвращает либо найденное значение, либо значение, созданное и сохраненное в файле Map
. Таким образом, в основном, computeIfAbsent
- это get
с put
, где значение put
в Map
возвращается методом. Этот метод гарантирует, что значение всегда существует для любого искомого ключа, но может быть расточительным в качестве замены get
, поскольку он всегда будет приводить к put
в тех случаях, когда вы ищете ключ, который не существует.
Карта имеет нулевую проблему
Одна проблема с использованием Map
заключается в том, что такие реализации, как HashMap
, допускают null
ключей, значений и возвратов. Если мы проигнорируем нулевые ключи на секунду, проблема со значениями и возвратами null
заключается в том, что если вы ищете ключ, который не существует в Map
, вы получите обратно null
. Вы можете попытаться защитить свой код от возможности проверки того, что Map
возвращает null при вызове get
, или с помощью более безопасного метода, такого как getOrDefault
, который может возвращать пустую коллекцию в случае многозначного Map
по умолчанию. Реальным решением было бы создать тип Map
, который знает, что отсутствующий ключ должен привести к возврату пустого Collection
при вызове get
. Это то, что делает Multimap
.
Не шутите с Картами с несколькими значениями
Если вам нужна многозначная поддержка Map
, рассмотрите возможность использования типа Multimap
из библиотеки, такой как Eclipse Collections, Google Guava или Apache Commons Collections. Метод put
для Multimap
будет знать, что значения являются многозначными, и должен автоматически вызывать add
для контейнеров значений. Метод get
для Multimap
знает, когда ключ не содержится в Multimap
, и вместо этого следует вернуть пустой Collection
. Дело в том, что Multimap
имеет более глубокие знания о типе значения, которым он управляет. Map
может быть предоставлен тип значения через дженерики, но он не знает, что тип значения должен быть типом Collection
.
Использование Multimap в Eclipse Collections
В следующем коде показано решение, эквивалентное приведенному выше коду Map, с использованием типа Multimap
из Eclipse Collections.
Во-первых, я создаю определенный тип Multimap
, который в данном случае является MutableListMultimap
. Затем я могу просто вызвать put с каждым ключом и значением. Multimap
знает, что нужно создать резервный контейнер Collection
(в данном случае MutableList
) для каждого нового ключа. Наконец, вызов multimap.get(“D”)
возвращает пустой List
. Этот List
не хранится в Multimap
, поэтому Multimap останется разреженным и будет содержать только ключи с фактическими значениями.
Типы мультикарт в Eclipse Collections
В Eclipse Collections есть несколько конкретных типов Multimap. Есть интерфейсы Readable
, Mutable
и Immutable
. Multimap
— это родительский интерфейс. MutableListMultimap
— это листовой интерфейс. Ниже приведены примеры основных типов бетона Multimap
, которые можно создать с помощью фабрики Multimaps
.
Для Multimap
существуют определенные типы, основанные на контейнерах значений (например, List
, Set
, Bag
). Для этих типов могут существовать специализации, а иногда и оптимизации.
GroupBy должен возвращать Multimap
Eclipse Collections — это единственная библиотека Java, о которой я знаю на сегодняшний день, которая возвращает Multimap
из своих groupBy
методов для каждого из своих основных Collection
типов. Каждый конкретный тип, такой как MutableList
или MutableSet
, будет возвращать соответствующий тип Multimap
в своем методе groupBy
на основе своего типа. MutableList
возвращает MutableListMultimap
из своего метода groupBy
, а MutableSet
возвращает MutableSetMultimap
. Ниже приведен пример использования groupBy
в Eclipse Collections.
Дополнительные примеры groupBy
можно найти в следующем блоге.
Дополнительная информация о мультикарте коллекций Eclipse
Нихил Нанивадекар несколько лет назад написал блог о Multimaps в Eclipse Collections. Он дает более подробные объяснения реализации.
Краткое содержание
Вам нужна карта с поддержкой ключей и нескольких значений? Рассмотрите возможность использования Multimap
из коллекций Eclipse. Если вы уже используете другие типы Collection
из коллекций Eclipse, методы groupBy
предоставят вам простой доступ к созданию соответствующих типов Multimap
.
Я являюсь руководителем и ответственным за проект OSS Eclipse Collections в Eclipse Foundation. Eclipse Collections открыт для пожертвований. Если вам нравится библиотека, сообщите нам об этом, пометив ее звездочкой на GitHub.