Search code examples
jvmkotlinnullablenon-nullable

In Kotlin, how do I idiomatically access nullable nested map values, or return a default?


Quick Kotlin best practices question, as I couldn't really work out the best way to do this from the documentation.

Assume I have the following nested map (typing specified explicitly for the purpose of this question):

val userWidgetCount: Map<String, Map<String, Int>> = mapOf(
        "rikbrown" to mapOf(
                "widgetTypeA" to 1,
                "widgetTypeB" to 2))

Can the following mode be any more succinct?

 fun getUserWidgetCount(username: String, widgetType: String): Int {
    return userWidgetCount[username]?.get(widgetType)?:0
}

In other words, I want to return the user widget count iff the user is known and they have an entry for that widget type, otherwise zero. In particular I saw I can use [] syntax to access the map initially, but I couldn't see a way to do this at the second level after using ?..


Solution

  • I would use an extension operator method for that.

    // Option 1
    operator fun <K, V> Map<K, V>?.get(key: K) = this?.get(key)
    // Option 2
    operator fun <K, K2, V> Map<K, Map<K2, V>>.get(key1: K, key2: K2): V? = get(key1)?.get(key2)
    

    Option 1:

    Define an extension that provides get operator for nullable map. In Kotlin's stdlib such approach appears with Any?.toString() extension method.

    fun getUserWidgetCount(username: String, widgetType: String): Int {
        return userWidgetCount[username][widgetType] ?: 0
    }
    

    Option 2:

    Create a special extension for map of maps. In my opinion, it is better because it shows the contract of the map of maps better than two gets in a row.

    fun getUserWidgetCount(username: String, widgetType: String): Int {
        return userWidgetCount[username, widgetType] ?: 0
    }