Java ☕️ Maps 🗺 on the Kotlin.
Curious how Kotlin resolve the Java platform’s map?
Most of the Kotlin developers are migrated from the Java environment, they are pretty well versed with uses-cases and application of Collection Framework in the Java platform, but applying the same knowledge in a Kotlin codebase isn’t guaranteed to work always. You could end up with a spaghetti codebase base having a long trailing function and making hacks to achieve a functionality that could easily be solved using Kotlin’s standard functions easily. Kotlin stdlib which offers generic interfaces, classes, and functions for creating, populating, and managing Collections of any type.
In Today’s article, we will try to understand how Kotlin catered to Java Maps in his its colors. Disclaimer This article is specific to Kotlin JVM as collection implementation varies with the platform you are targeting in Kotlin. I’m Chetan Gupta, I do tech stuff, don’t forget to checkout from personal blogs from AndroidBites, without any delays, Let’s get started.
Note:
This Post is given `Silver award` in Reddit at r/android_devs,
thanks community for supporting my blogs and it really motivating me!
Map 🗺
It’s a collection of key-value pairs, mainly focus on retrieving a value against the key.
- Keys are unique and similar to the index of an array.
- A map can hold only one value against a key.
- The map is a read-only collection but for the sake of understanding, I will be addressing it as Immutable*.
- The modifying part is supported using Mutable maps, discussed later in the article.
Map<K, V>
is not an inheritor of the Collection Interface, but it’s the part of the Kotlin Collection type.
Entries 🚪
An entry represents a key/value pair in a map.
A map contains a Set<Entry<K,V>>
type entries to store its key/value, since its a Set, the uniqueness is enforced into the map entries.
Even though an entry
is representing a key-value pair in a map, there is no way to directly create a map using it i.e if you can see possible ways we can create a map :
There is no function which creates a map using the Entry, if you check Entry
Interface
from docs, you will see
Entry can be converted to Pair but not to a map directly (like a SingletonMap), even if you focus on entries in the map which are Set<Entry<K, V>>
there is no function that converts a Set<Entry<String, Int>>
into Map.
Since there is no direct support of entries to map, hence we can conclude that it’s used only as an internal implementation of key/value entries, but for the outside world it has to implement using Pair type.
Since we are creating Maps using Pair
, let’s focus on what is it?
Pair 👥
A Pair represents a generic pair of two values. It is a separate data structure, which is not a part of the Collection Framework. It can be used for any purpose.
It isn’t necessary that the first
and the second
the element of the Pair
holds any relation with each other, but Entry’s first element i.e key
has a relation with the second element i.e value
.
But since Entry
can’t be used to create maps directly there was no logical point in having a standard extension that converts Pair
into Map.Entry
type, thus stdlib doesn’t have Pair.toEntry()
function.
There is a discussion in the form regarding it but it goes nowhere.
Since Pair
are used to create Map
, the extension below supports that Idea.
Map
is the base Interface for AbstractMap
and MutableMap
, so all the core ADT functions such as get
, put
, contains
, containsKey
, isEmpty
, size
etc are implemented in it.
Check out the complete list of base functions from docs :
mapOf 👷♂️
If you have focused on Map signature interface Map<K, out V>
, it’s an interface, i.e it needs to have an implementing class.
In Kotlin, we have three functions for implementing maps and all of them are resolved using different implementations of Map.
So if you are working with a map which has more than one entry, is highly likely to be resolved by using an implementation of LinkedHashMap
. We will know about it later in the article.
TLDR ☕️
Maps :
- Maps are read-only key/value pair of collection
- They use Entry to represent the internal state of key/value
- You use Pairs to create a map
- Maps implementation varies but is mostly resolved with LinkedHashMap
Mutable Map 📝
As the name suggests, it’s a mutable implementation of a Map
. It’s a modifiable version of the map.
Similar to Map, MutableMap has MutableEntry
that represents a key/value pair but unlike Entry it is mutable :
Entries in the mutableMap
is now a MutableSet
:
Since Map
was immutable*(read-only), there was no mutable function such as :
All the functions available in the Map are overridden using mutable type variants, You can check them out from docs :
Mutable Pair? 🤔
Since you now see everything is implemented in Mutable Maps using mutable types, means Pair which are used to construct mutable map should have a mutable implementation as well, isn’t it?
Logically your thinking is right but only if you look it in terms of Collection, Pairs are not part of collection.
The immutability and Mutability collections concept is introduced to provide a read-only protection*. This helps Kotlin Compiler to show an error at compile-time rather than runtime, for example In Java, java.util.Collections.unmodifiableList(java.util.List)
the error would be only visible to the user when he tries to update the unmodifiable list at runtime.
read-only protections, are used to safeguard values in a collection from accidental
updates
So how do we update Pair values?
It’s easy, you can directly use the copy constructor, for example :
The last thing in your mind would be, do we need to use ListOf<Pair<K,V>>
or MutableListOf<Pair<K,V>>
to create a mutable map?
To answer this, you need to know both List
and MutableList
both are of an iterable
type so doesn’t matter, you can create a map using both.
Other part is you can’t directly convert a List
or MutableList
to MutableMap
, there is no direct extension available :
MutableMap is the base interface of AbstractMutableMap
, HashMaps
and LinkedHashMap
.
mutableMapOf 👷♂️
Similar to Map signature, interface MutableMap<K, out V>
, it’s an interface, i.e it needs to have an implementing class.
In Kotlin, we have two function implementation of these and both of them is resolved using LinkedHashMap
TLDR ☕️
Mutable Maps :
- Mutable Maps are modifiable key/value pairs of collection therefore contain functions such as put, remove, clear etc that can modify the map.
- They use MutableEntry to represent the internal state of key/value
- Pairs don’t have mutable counter-part, Pairs are used to create the map, then that map is transformed to MutableMap.
- All of the function implementations is resolved by LinkedHashMap
HashMap 📝
In Kotlin JVM, HashMap is a type alias for Java’s HashMap
HashMap in Java is a Hash table based implementation of the (Mutable) Map interface.
- Insertion Order is not preserved, insertion is based on the hashcode of keys, not the values
- Duplicate keys entry is not allowed
- Heterogeneous key/value entry is allowed
- Null keys are allowed but only once, you can store any null values
NOTE.
Even if Kotlin uses typealias
and call Java Hashmap the interpolation with Kotlin maps its return types to the MutableMap
interface of Kotlin, i.e when you call hashMap.entries
you will get MutableSet<MutableEntry>
not Java’s Set<Entry>
.
Learn more about all the APIs of HashMap from:
hashMapOf 👷♂️
Kotlin provides two implementations to create HashMap
Another way by which you can create a hashmap is by creating an object directly using any of the available java constructors.
Convert Map to HashMap?
There is no direct extension to convert map to hashmap as it was available in mutable map, so you can :
TLDR ☕️
Hash Maps:
- They are a direct port of
java.util.HashMap
, whose underlying implementation is based onHashTable
. - Insertion Order is not preserved, because it’s sorted according to
hashcode
of the keys - No special Kotlin standard extension is available over them, you can directly create them using constructor or use standard static factory functions of Kotlin.
- Mutable collection in nature.
LinkedHashMap ⛓📝
In Kotlin JVM, similar to HashMap, LinkedHashMap is a type alias for Java’s LinkedHashMap
LinkedHashMap in Java is a Hash table
and LinkedList
based implementation of the (Mutable) Map interface.
- Doubly LinkedList is used to preserve the order of insertion.
- Features are similar to HashMap including methods and constructors.
- Useful to create a
Cache object
that can expire data using some criteria that you define or LRUs ( least recently used ) by overriding theremoveEldestEntry()
Check out my LRU implementation in Repository.
linkedMapOf ️️👷♂️
Kotlin provides two implementations to create LinkedHashMap
Other way by which you can create a Linkedhashmap
is by creating an object directly using any of the available java constructors.
Convert Map to LinkedHashMap?
There is no direct extension to convert map
to hashmap
as it was available in mutableMap
, so you can :
TLDR ☕️
LinkedHashMaps:
- They are a direct port of
java.util.LinkedHashMap<K,V>
, whose underlying implementation is based onHashTable
andLinkedList
. - Doubly LinkedList is used to preserve the order of insertion
- No special Kotlin standard extension are available over them, you can directly create them using constructors or use standard static factory functions of Kotlin.
- Mutable collection in nature.
Bonus Points: 🤩
Since you made it this far in the post, here is your reward!
Some points that you need to know about maps :
HashMap/LinkedHashMap
- They are not thread-safe, doesn’t have synchronized functions
- The null key is allowed only once
- Performs faster in the multithreaded environment due to lack of synchronization
- They are not a legacy DS, HashMap introduced in 1.2, LinkedHashMap introduced in 1.4
HashTable
- They are thread-safe
- The null key isn’t allowed
- Perform slow in the multithreaded environment due to synchronization
- It is a legacy DS, introduced in 1.0
Conclusion 💆🏻♀️
Hopefully, you understand how Kotlin handles Collection over the JVM platform and some of the key points such as:
- Entries that can’t be directly converted to Map,
- Pair doesn’t have Mutable type,
- It's not always true that your map is a linkedHashMap
- Kotlin JVM resolves Hashmap and LinkedHashMap using Java APIs. etc
Hope you find the post informative, if like more such content you can gladly follow up on my personal blog at chetangupta.net
, you can use the same link to contact me.
Until next time, Happy Hacking! 👨🏻💻.