1. Обзор
В этом уроке мы узнаем , как построить карту с примитивными ключами и значениями.
Как мы знаем, основные Java Maps
не позволяют хранить примитивные ключи или значения . Вот почему мы представим несколько внешних сторонних библиотек, которые обеспечивают реализации примитивных карт.
2. Коллекции затмений
Eclipse Collections — это высокопроизводительная среда сбора данных для Java . Он предоставляет улучшенные реализации, а также некоторые дополнительные структуры данных, включая несколько примитивных коллекций.
2.1. Изменяемые и неизменяемые карты
Давайте создадим пустую карту, где и ключи, и значения являются примитивными целыми
числами. Для этого мы будем использовать фабричный класс IntIntMaps
:
MutableIntIntMap mutableIntIntMap = IntIntMaps.mutable.empty();
Фабричный класс IntIntMaps
— наиболее удобный способ создания карт-примитивов . Это позволяет нам создавать как изменяемые, так и неизменяемые экземпляры желаемого типа карты. В нашем примере мы создали изменяемый экземпляр IntIntMap
. Точно так же мы можем создать неизменяемый экземпляр, просто заменив вызов
статической фабрики IntIntMaps.mutable на IntIntMaps.immutable
:
ImmutableIntIntMap immutableIntIntMap = IntIntMaps.immutable.empty();
Итак, давайте добавим пару ключ-значение в нашу изменяемую карту:
mutableIntIntMap.addToValue(1, 1);
Точно так же мы можем создавать смешанные карты с парами ключ-значение эталонного и примитивного типов. Давайте создадим карту со строковыми
ключами и двойными
значениями:
MutableObjectDoubleMap dObject = ObjectDoubleMaps.mutable.empty();
Здесь мы использовали класс фабрики ObjectDoubleMaps
для создания изменяемого экземпляра для MutableObjectDoubleMap
.
Теперь добавим несколько записей:
dObject.addToValue("price", 150.5);
dObject.addToValue("quality", 4.4);
dObject.addToValue("stability", 0.8);
2.2. Примитивное дерево API
В Eclipse Collections есть базовый интерфейс PrimitiveIterable.
Это базовый интерфейс для каждого из примитивных контейнеров библиотеки. Все они называются PrimitiveTypeIterable
, где PrimitiveType
может быть Int, Long
, Short
, Byte
, Char
, Float
, Double
или Boolean
.
Все эти базовые интерфейсы, в свою очередь, имеют свое дерево реализаций XY
Map
, которое делится на то, является ли карта mutable или immutable . Например, для IntIntMap
у нас есть MutableIntIntMap
и ImmutableIntIntMap
.
Наконец, как мы видели выше, у нас есть интерфейсы, охватывающие все виды комбинаций типов для ключей и значений как для примитивных, так и для объектных значений . Так, например, у нас может быть IntObjectMap<K>
для примитивного ключа со значением Object
или ObjectIntMap<K>
для противоположного случая.
3. HPPC
HPPC — это библиотека, ориентированная на высокую производительность и эффективность использования памяти. Это означает, что в библиотеке меньше абстракций, чем в других. Тем не менее, это имеет преимущество, заключающееся в том, что внутренние компоненты подвергаются полезным низкоуровневым манипуляциям. Он предоставляет как карты, так и наборы.
3.1. Простой пример
Начнем с создания карты с ключом int и значением
long
. Использование этого довольно знакомо:
IntLongHashMap intLongHashMap = new IntLongHashMap();
intLongHashMap.put(25, 1L);
intLongHashMap.put(150, Long.MAX_VALUE);
intLongHashMap.put(1, 0L);
intLongHashMap.get(150);
HPPC предоставляет карты для всех комбинаций ключей и значений:
- Примитивный ключ и примитивное значение
- Примитивный ключ и значение типа объекта
- Ключ объектного типа и примитивное значение
- Ключ и значение типа объекта
Карты объектного типа поддерживают дженерики:
IntObjectOpenHashMap<BigDecimal>
ObjectIntOpenHashMap<LocalDate>
Первая карта имеет примитивный ключ int и значение
BigDecimal
. Вторая карта имеет LocalDate
для своих ключей и int
для своих значений .
3.2. Хэш-карты против точечных карт
Из-за того, как традиционно реализуются функции хэширования и распределения ключей, у нас могут возникнуть коллизии при хешировании ключей. В зависимости от того, как распределяются ключи, это может привести к проблемам с производительностью на огромных картах. По умолчанию HPPC реализует решение, позволяющее избежать этой проблемы.
Однако место для карт, имеющих более простую функцию распределения, все же остается. Это полезно , если карты используются в качестве таблиц поиска или для подсчета, или если они не требуют большого количества операций записи после загрузки . HHPC предоставляет точечные карты
для еще большего повышения производительности.
Все классы точечных карт поддерживают то же соглашение об именах, что и карты, но вместо этого используют слово Scatter
:
Интскаттерсет
IntIntScatterMap
IntObjectScatterMap<BigDecimal>
4. Фасттил
Fastutil — это быстрая и компактная платформа , предоставляющая коллекции для конкретных типов, включая карты примитивных типов.
4.1. Быстрый пример
Аналогично Eclipse Collections и HPPC. Fastutil также предоставляет ассоциативные карты типа «примитив-примитив» и «примитив-объект».
Давайте создадим карту int
to boolean :
Int2BooleanMap int2BooleanMap = new Int2BooleanOpenHashMap();
А теперь добавим несколько записей:
int2BooleanMap.put(1, true);
int2BooleanMap.put(7, false);
int2BooleanMap.put(4, true);
Затем мы можем получить из него значения:
boolean value = int2BooleanMap.get(1);
4.2. Итерация на месте
Стандартные коллекции JVM, реализующие интерфейс Iterable
, обычно создают новый временный объект итератора на каждом шаге итерации. С огромными коллекциями это может создать проблему со сборкой мусора.
Fastutil предоставляет альтернативу, которая значительно смягчает это:
Int2FloatMap map = new Int2FloatMap();
//Add keys here
for(Int2FloatMap.Entry e : Fastutil.fastIterable(map)) {
//e will be reused on each iteration, so it will be only one object
}
Fastutil также предоставляет метод fastForeach
. Это возьмет функциональный интерфейс Consumer
и выполнит лямбда-выражение для каждого цикла:
Int2FloatMap map = new Int2FloatMap();
//Add keys here
Int2FloatMaps.fastForEach(map , e -> {
// e is also reused across iterations
});
Это очень похоже на стандартную конструкцию foreach
в Java :
Int2FloatMap map = new Int2FloatMap();
//Add keys here
map.forEach((key,value) -> {
// use each key/value entry
});
5. Вывод
В этой статье мы узнали, как создавать карты-примитивы на Java с помощью Eclipse Collections, HPPC и Fastutil .
Как всегда, пример кода для этой статьи доступен на GitHub .