Kotlin学习之Map常用工具函数
Kotlin学习之Map常用工具函数
kotlin.collections.Maps.kt文件中定义了许多针对Map接口的工具函数,其中大多数是涉及函数式编程的高阶函数。今天只是介绍几个简单的函数。
一、Pair类与to()函数
Map接口表示一种“键->值”的数据结构,一个键对应一个值。但是在实现时,Map并没有维护键和值两个结构,而是一个个Entry对象,每个Entry对象表示一个键与值的对应关系,有三个属性:key、value和hash,因为hash只与key有关,所以可以视为只有两个属性:key和value。
Kotlin为了简化Map的创建,定义了一个新类:Pair,相当于简化版的Map.Entry类:
// kotlin.Tuple.kt
data class Pair<out A, out B>(
val first: A,
val second: B
) : Serializable {
override fun toString() = "($first, $second)"
}
上面的first相当于key、second相当于value,hashCode()充当了hash属性。
Kotlin还定义了一个to函数来创建Pair对象:
// kotlin.Tuple.kt
infix fun <A, B> A.to(that: B): Pair<A, B> = Pair(this, that)
这是一个infix修饰的中缀函数,也是A类对象的扩展函数,它接受一个B类的参数,使用被扩展的A类对象和作为参数的B类对象创建一个Pair对象。
val p1 = 1 to "Hello"
// 等价于 val p1 = 1.to("Hello")
val p2 = p1 to "World"
// p1: Pair<Int, String>
// p2: Pair<Pair<Int, String>, String>
二、mapOf()与mutableMapOf()函数
Kotlin的Map接口也提供了生成不可变Map的mapOf()函数和生成可变Map的mutableMapOf()函数。Map接口的两个函数只接受Pair对象作为参数:
inline fun <K, V> mapOf(): Map<K, V> = emptyMap()
fun <K, V> mapOf(pair: Pair<K, V>): Map<K, V> =
java.util.Collections.singletonMap(pair.first, pair.second)
fun <K, V> mapOf(vararg pairs: Pair<K, V>): Map<K, V> =
if (pairs.size > 0) linkedMapOf(*pairs) else emptyMap()
inline fun <K, V> mutableMapOf(): MutableMap<K, V> = LinkedHashMap()
fun <K, V> mutableMapOf(vararg pairs: Pair<K, V>): MutableMap<K, V> =
LinkedHashMap<K, V>(mapCapacity(pairs.size)).apply { putAll(pairs) }
注意:
- mapOf()和mutableMapOf()在元素数大于1时,都采用LinkedHashMap的实现方式。
- linkedMapOf(
*
pairs)是什么写法?这展开操作符,一般来说,给vararg函数传参数时,只能一个一个地传,如果想把一个数组传给vararg参数,可以在数组前面加个*
,告诉编译器“我不是把数组对象作为参数,而是把数组里的每个元素作为参数”。例如:
val array = intArrayOf(1, 2, 3)
val list = listOf(0, *array, 4, 5)
// list: List<Int> = [0, 1, 2, 3, 4, 5]
三、hashMapOf()与linkedMapOf()函数
hashMapOf()和LinkedMapOf()函数创建的都是可变Map:
inline fun <K, V> hashMapOf(): HashMap<K, V> = HashMap<K, V>()
fun <K, V> hashMapOf(vararg pairs: Pair<K, V>): HashMap<K, V> =
HashMap<K, V>(mapCapacity(pairs.size)).apply { putAll(pairs) }
inline fun <K, V> linkedMapOf(): LinkedHashMap<K, V> = LinkedHashMap<K, V>()
fun <K, V> linkedMapOf(vararg pairs: Pair<K, V>): LinkedHashMap<K, V> =
LinkedHashMap<K, V>(mapCapacity(pairs.size)).apply { putAll(pairs) }
四、解构函数
解构函数就是用operator关键字修饰的componentN()函数,这里的N是从1到5的整数。
Maps.kt中定义了两个解构函数:
inline operator fun <K, V> Map.Entry<K, V>.component1(): K = key
inline operator fun <K, V> Map.Entry<K, V>.component2(): V = value
都是Map.Entry的扩展函数,分别返回这个Entry的键和值,常用来遍历Map的键和值:
val map = mapOf(1 to 2, 3 to 4)
for((key, value) in map) {
println("$key -> $value")
}
// 1 -> 2
// 3 -> 4
五、plus()与minus()函数
Map.kt重载了操作符+和-,方便进行增删元素。
- 所有plus()和minus()函数都是不可变的Map的扩展函数,所以每次调用plus()或minus()函数都会产生一个新的Map,这在Map内元素很多时可能会产生性能问题。
- plus()和minus()函数有以下几种参数不同的重载形式:
- Array<out Pair<K,V>>:Pair数组
- Iterable<Pair<K,V>>:Pair集合
- Pair<K,V>:单个Pair对象
- Sequence<Pair<K,V>>:Pair序列
- Map<out K,V>:另一个Map
- 对于MutableMap,Maps.kt重载了+=(plusAgain()函数)和-=(minusAssign()函数)操作符,分别相当于调用put()/putAll()函数和remove()/removeAll()函数:
val mutableMap = mutableMapOf(1 to 2, 3 to 4)
mutableMap += arrayOf(1 to 2, 5 to 6)
// mutableMap = [1->2, 3->4, 5->6]
mutableMap -= 3
// mutableMap = [1->2, 5->6]
六、toMap()函数
Map.kt还提供了一系列toMap()函数,用来将其它数据形式的Pair对象转换为可变的Map,包括如下两种重载形式:
- 支持Array<out Pair<K,V>>、Iterable<Pair<K,V>>、Sequence<Pair<K,V>>和Map<out K,V>四种数据结构转换为Map。
- 支持无参和一个destination参数两种形式,前者直接将转换得到Map赋给自身,后者则会把转换成Map赋给destination。
七、改进的putAll()函数
Maps.kt 给 MutableMap 重载了三个新的 putAll() 函数,它们分别接受 Array<out Pair<K, V>>、Iterable<Pair<K, V>> 和 Sequence<Pair<K, V>> 对象。