Карта на примитивите в Java

1. Общ преглед

В този урок ще научим как да изградим карта с примитивни ключове и стойности.

Както знаем, основната Java Map не позволява съхранението на примитивни ключове или стойности. Ето защо ще представим някои външни библиотеки на трети страни, които предоставят примитивни реализации на карти.

2. Колекции Eclipse

Eclipse Collections е високоефективна рамка за събиране на Java . Той осигурява подобрени реализации, както и някои допълнителни структури от данни, включително няколко примитивни колекции.

2.1. Изменяеми и неизменяеми карти

Нека създадем празна карта, където и ключовете, и стойностите са примитивни int s. За това ще използваме фабричния клас IntIntMaps :

MutableIntIntMap mutableIntIntMap = IntIntMaps.mutable.empty();

В IntIntMaps класа фабрика е най-удобният начин за създаване на примитивни карти . Позволява ни да създаваме както променливи, така и неизменяеми копия на желания тип карта. В нашия пример създадохме изменяемия екземпляр на IntIntMap . По същия начин можем да създадем неизменим екземпляр, като просто заменим статичното фабрично повикване IntIntMaps.mutable с IntIntMaps.immutable :

ImmutableIntIntMap immutableIntIntMap = IntIntMaps.immutable.empty();

И така, нека добавим двойка ключ, стойност към нашата изменяема карта:

mutableIntIntMap.addToValue(1, 1);

По същия начин можем да създадем смесени карти с референтен и примитивен тип двойки ключ-стойност. Нека създадем карта с ключове String и двойни стойности:

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 , което е разделено на това дали картата е променлива или неизменяема . Като пример за IntIntMap , ние имаме MutableIntIntMap и ImmutableIntIntMap .

И накрая, както видяхме по-горе, имаме интерфейси за покриване на всички видове комбинации от типове за ключове и стойности както за примитивни, така и за обектни стойности . Така например, можем да имаме IntObjectMap за примитивен ключ със стойност на Object или ObjectIntMap за обратния му случай.

3. HPPC

HPPC е библиотека, насочена към висока производителност и ефективност на паметта. Това означава, че библиотеката има по-малко абстракция от другите. Това обаче има предимството да изложи вътрешните органи на полезна манипулация на ниско ниво. Той предоставя както карти, така и набори.

3.1. Един прост пример

Нека започнем със създаването на карта, която има ключ int и дълга стойност. Използването на това е доста познато:

IntLongHashMap intLongHashMap = new IntLongHashMap(); intLongHashMap.put(25, 1L); intLongHashMap.put(150, Long.MAX_VALUE); intLongHashMap.put(1, 0L); intLongHashMap.get(150);

HPPC предоставя карти за всички комбинации от клавиши и стойности:

  • Примитивен ключ и примитивна стойност
  • Примитивен ключ и стойност от обектен тип
  • Ключ от тип обект и примитивна стойност
  • Както ключ от обект, така и стойност

Обектните карти поддържат генерични продукти:

IntObjectOpenHashMap ObjectIntOpenHashMap 

Първата карта има примитивен ключ int и BigDecimal стойност. Втората карта има LocalDate за своите ключове и int за своите стойности

3.2. Hash Maps срещу Scatter Maps

Поради начина, по който традиционно се изпълняват функциите за хеширане и разпределение на ключове, може да имаме сблъсъци при хеширане на ключовете. В зависимост от начина на разпределение на ключовете, това може да доведе до проблеми с производителността на огромни карти. По подразбиране HPPC прилага решение, което избягва този проблем.

Все пак има място за карти, които имат по-проста функция на разпределение. Това е полезно, ако картите се използват като справочни таблици или за преброяване, или ако не изискват много операции за запис след зареждане . HHPC предоставя Scatter Maps, за да подобри още повече производителността.

Всички класове разпръснати карти поддържат същото споразумение за именуване като картите, но вместо това използват думата Scatter :

  • IntScatterSet
  • IntIntScatterMap
  • IntObjectScatterMap

4. Фастутил

Fastutil е бърза и компактна рамка, която предоставя специфични за типа колекции, включително примитивни типови карти.

4.1. Бърз пример

Подобно на Eclipse Collections и HPPC. Fastutil също така предоставя примитивни към примитивни и примитивни към обект типизирани карти на асоциации.

Let's create an int to boolean map:

Int2BooleanMap int2BooleanMap = new Int2BooleanOpenHashMap();

And now, let's add some entries:

int2BooleanMap.put(1, true); int2BooleanMap.put(7, false); int2BooleanMap.put(4, true);

Then, we can retrieve values from it:

boolean value = int2BooleanMap.get(1);

4.2. In-Place Iteration

Standard JVM collections that implement the Iterable interface usually create a fresh temporary iterator object at each iteration step. With huge collections, this can create a garbage collection issue.

Fastutil provides an alternative that greatly mitigates this:

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 also provides the fastForeach method. This will take a Consumer functional interface and perform a lambda-expression for each loop:

Int2FloatMap map = new Int2FloatMap(); //Add keys here Int2FloatMaps.fastForEach(map , e -> { // e is also reused across iterations }); 

This is very similar to the standard Java foreach construct:

Int2FloatMap map = new Int2FloatMap(); //Add keys here map.forEach((key,value) -> { // use each key/value entry }); 

5. Conclusion

В тази статия научихме как да създаваме примитивни карти в Java с помощта на Eclipse Collections, HPPC и Fastutil .

Както винаги, примерният код за тази статия е достъпен в GitHub.