Map-specific operations
A Map models unique keys associated with values. Most interview mistakes come from confusing an absent key with a nullable value, silently overwriting a key, or using a non-atomic read-then-write sequence.
Lookup choices communicate policy
fun main() {
val scores = mapOf("Rakesh" to 90)
println(scores["Rakesh"]) // 90
println(scores["Missing"]) // null
println(scores.getOrDefault("Missing", 0)) // 0
println(scores.getOrElse("Missing") { -1 }) // -1
val failure = runCatching { scores.getValue("Missing") }
println(failure.exceptionOrNull()!!::class.simpleName)
}
map[key]returnsV?.getValuethrows for an absent key and is suitable when absence violates an invariant.getOrElsecomputes a fallback for this read but does not store it.getOrDefaultreturns the supplied default.
With Map<K, V?>, map[key] == null cannot distinguish “absent key” from “present key with null value”; use containsKey when that distinction matters.
getOrPut stores a missing value
fun main() {
val cache = mutableMapOf<String, MutableList<String>>()
cache.getOrPut("Android") { mutableListOf() }.add("Rakesh")
cache.getOrPut("Android") { mutableListOf() }.add("Sam")
println(cache) // {Android=[Rakesh, Sam]}
}
getOrPut is convenient, but a normal mutable map does not make compound access thread-safe. Use an ownership/concurrency strategy appropriate to the platform and map implementation.
Transforming and filtering maps
fun main() {
val prices = mapOf("phone" to 500.0, "case" to 20.0, "cable" to 10.0)
println(prices.mapKeys { (key, _) -> key.uppercase() })
println(prices.mapValues { (_, value) -> value * 1.18 })
println(prices.filterKeys { it.startsWith("c") })
println(prices.filterValues { it >= 20.0 })
}
If mapKeys produces duplicate keys, later entries overwrite earlier results. Key transformation therefore needs the same collision policy as associateBy.
Addition, removal, and mutation
fun main() {
val original = mapOf("A" to 1, "B" to 2)
val replaced = original + ("A" to 100)
val removed = replaced - "B"
println(original) // {A=1, B=2}
println(replaced) // {A=100, B=2}
println(removed) // {A=100}
val mutable = original.toMutableMap()
mutable["C"] = 3
mutable.remove("A")
println(mutable) // {B=2, C=3}
}
Interview questions
- How do you distinguish an absent key from a present null value?
- How does
getOrElsediffer fromgetOrPut? - What happens when
mapKeyscreates collisions? - Does
map + pairmutate the original map?