Kotlin中Map两种取值方式下值的可空性差异原因
Kotlin groupBy返回Map的取值可空性差异问题
我是Kotlin新手,在Android Jetpack Compose初学者课程练习中遇到一个问题:通过groupBy方法得到的LinkedHashMap,使用[]运算符取值时,返回值类型为List?,编译器要求必须进行空安全调用(?.或!!.);而通过forEach遍历该Map时,遍历得到的值类型为List,无需空检查,添加空安全调用还会提示不必要。请问为何两种取值方式下值的可空性会存在差异?
完整代码
enum class Daypart { MORNING, AFTERNOON, EVENING } data class Event ( val title: String, val description: String? = null, val daypart: Daypart, val duration: Int ) fun main() { val event1 = Event(title = "Wake up", description = "Time to get up", daypart = Daypart.MORNING, duration = 0) val event2 = Event(title = "Eat breakfast", daypart = Daypart.MORNING, duration = 15) val event3 = Event(title = "Learn about Kotlin", daypart = Daypart.AFTERNOON, duration = 30) val event4 = Event(title = "Practice Compose", daypart = Daypart.AFTERNOON, duration = 60) val event5 = Event(title = "Watch latest DevBytes video", daypart = Daypart.AFTERNOON, duration = 10) val event6 = Event(title = "Check out latest Android Jetpack library", daypart = Daypart.EVENING, duration = 45) val events = mutableListOf<Event>(event1, event2, event3, event4, event5, event6) val daypartEvents = events.groupBy { it.daypart } print(daypartEvents::class.simpleName) println("Morning: ${daypartEvents[Daypart.MORNING]?.size}") daypartEvents.forEach { (daypart, events) -> println("$daypart: ${events.size}") } }
问题解答
1. Map的[]运算符(get方法)的定义
Kotlin中Map接口的get运算符(也就是你用的[]),方法签名是operator fun get(key: K): V?。这个设计的核心原因是:编译器无法提前确定你传入的key一定存在于Map中——哪怕你的场景里groupBy生成的Map包含了所有枚举值,但从Map的通用定义来看,任何key都可能不存在,所以返回值必须标记为可空类型V?,强制你处理空情况。
2. forEach遍历的逻辑
当你调用Map的forEach方法时,遍历的是Map中实际存在的键值对。forEach的参数是一个接收Map.Entry<K, V>的函数,每个Entry都是Map里已经确认存在的条目,对应的value必然是非空的V,而不是V?。所以在遍历过程中,你拿到的events是确定存在的List<Event>,自然不需要空安全调用。
额外小技巧
如果想避免使用[]时的空检查,可以用getOrDefault方法直接指定默认值:
println("Morning: ${daypartEvents.getOrDefault(Daypart.MORNING, emptyList()).size}")
这样即使key不存在,也会返回一个空列表,无需处理可空性。
内容的提问来源于stack exchange,提问作者Aaron
相关产品推荐
相关产品推荐

