- 5.5 Map
- 5.5.1 Map概述
- 5.5.2 创建Map
- 5.5.3 访问Map的元素
- 5.5.4 Map操作符函数
- containsKey(key: K): Boolean
- containsValue(value: V): Boolean
- component1() component2()
- Map.Entry<K, V>.toPair(): Pair<K, V>
- getOrElse(key: K, defaultValue: () -> V): V
- getValue(key: K): V
- getOrPut(key: K, defaultValue: () -> V): V
- iterator(): Iterator<Map.Entry<K, V>>
- mapKeys(transform: (Map.Entry<K, V>) -> R): Map<R, V>
- mapValues(transform: (Map.Entry<K, V>) -> R): Map<K, R>
- filterKeys(predicate: (K) -> Boolean): Map<K, V>
- filterValues(predicate: (V) -> Boolean): Map<K, V>
- filter(predicate: (Map.Entry<K, V>) -> Boolean): Map<K, V>
- Iterable<Pair<K, V>>.toMap(destination: M): M
- Map<out K, V>.toMutableMap(): MutableMap<K, V>
- plus minus
- put(key: K, value: V): V?
- putAll(from: Map<out K, V>): Unit
- MutableMap<out K, V>.remove(key: K): V?
- MutableMap<K, V>.clear(): Unit
5.5 Map
5.5.1 Map概述
Map是一种把键对象Key和值对象Value映射的集合,它的每一个元素都包含一对键对象和值对象(K-V Pair)。 Key可以看成是Value 的索引,作为key的对象在集合中不可重复(uniq)。
如果我们从数据结构的本质上来看,其实List就是Key是Int类型下标的特殊的Map。而Set也是Key为Int,但是Value值不能重复的特殊Map。
Kotlin中的Map与List、Set一样,Map也分为只读Map和可变的MutableMap。
Map没有继承于Collection接口。其类图结构如下:

在接口interface Map<K, out V>中,K是键值的类型,V是对应的映射值的类型。这里的out V表示类型为V或V的子类。这是泛型的相关知识,我们将在下一章节中介绍。
其中,Entry<out K, out V>中保存的是Map的键值对。
5.5.2 创建Map
跟Java相比不同的是,在Kotlin中的Map区分了只读的Map和可编辑的Map(MutableMap、HashMap、LinkedHashMap)。
Kotlin没有自己重新去实现一套集合类,而是在Java的集合类基础上做了一些扩展。
我们知道在Java中,根据内部数据结构的不同,Map 接口通常有多种实现类。
其中常用的有:
- HashMap
HashMap是基于哈希表(hash table)的 Map 接口的实现,以key-value的形式存在。在HashMap中,key-value是一个整体,系统会根据hash算法来来计算key-value的存储位置,我们可以通过key快速地存取value。它允许使用 null 值和 null 键。
另外,HashMap中元素的顺序,随着时间的推移会发生变化。
- TreeMap
使用红黑二叉树(red-black tree)的 Map 接口的实现。
- LinkedHashMap
还有继承了HashMap,并使用链表实现的LinkedHashMap。LinkedHashMap保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录是先插入的记录。简单说,LinkedHashMap是有序的,它使用链表维护内部次序。
我们在使用Kotlin创建Map的时候,实际上大部分都是调用Java的Map的方法。
下面我们就来介绍Map的创建以及基本操作函数。
mapOf()
创建一个只读空Map。
1. >>> val map1 = mapOf<String, Int>()
2. >>> map1.size
3. 0
4. >>> map1.isEmpty()
5. true
我们还可以用另外一个函数创建空Map:
1. >>> val map2 = emptyMap<String, Int>()
2. >>> map2.size
3. 0
4. >>> map2.isEmpty()
5. true
空Map都是相等的:
1. >>> map2==map1
2. true
这个空Map是只读的,其属性和函数返回都是预定义好的。其代码如下:
1. private object EmptyMap : Map<Any?, Nothing>, Serializable {
2. private const val serialVersionUID: Long = 8246714829545688274
4. override fun equals(other: Any?): Boolean = other is Map<*,*> && other.isEmpty()
5. override fun hashCode(): Int = 0
6. override fun toString(): String = "{}"
8. override val size: Int get() = 0
9. override fun isEmpty(): Boolean = true
11. override fun containsKey(key: Any?): Boolean = false
12. override fun containsValue(value: Nothing): Boolean = false
13. override fun get(key: Any?): Nothing? = null
14. override val entries: Set<Map.Entry<Any?, Nothing>> get() = EmptySet
15. override val keys: Set<Any?> get() = EmptySet
16. override val values: Collection<Nothing> get() = EmptyList
18. private fun readResolve(): Any = EmptyMap
19. }
mapOf(pair: Pair<K, V>): Map<K, V>
使用二元组Pair创建一个只读Map。
1. >>> val map = mapOf(1 to "x", 2 to "y", 3 to "z")
2. >>> map
3. {1=x, 2=y, 3=z}
4. >>> map.get(1)
5. x
6. >>> map.get(3)
7. z
8. >>> map.size
9. 3
10. >>> map.entries
11. [1=x, 2=y, 3=z]
这个创建函数内部是调用的LinkedHashMap构造函数,其相关代码如下:
1. pairs.toMap(LinkedHashMap(mapCapacity(pairs.size)))
如果我们想编辑这个Map, 编译器会直接报错
1. >>> map[1]="a"
2. error: unresolved reference. None of the following candidates is applicable because of receiver type mismatch:
3. @InlineOnly public operator inline fun <K, V> MutableMap<Int, String>.set(key: Int, value: String): Unit defined in kotlin.collections
4. @InlineOnly public operator inline fun kotlin.text.StringBuilder /* = java.lang.StringBuilder */.set(index: Int, value: Char): Unit defined in kotlin.text
5. map[1]="a"
6. ^
7. error: no set method providing array access
8. map[1]="a"
9. ^
因为在不可变(Immutable)Map中,根本就没有提供set函数。
mutableMapOf()
创建一个空的可变的Map。
1. >>> val map = mutableMapOf<Int, Any?>()
2. >>> map.isEmpty()
3. true
4. >>> map[1] = "x"
5. >>> map[2] = 1
6. >>> map
7. {1=x, 2=1}
该函数直接是调用的LinkedHashMap()构造函数。
mutableMapOf(vararg pairs: Pair<K, V>): MutableMap<K, V>
创建一个可编辑的MutableMap对象。
1. >>> val map = mutableMapOf(1 to "x", 2 to "y", 3 to "z")
2. >>> map
3. {1=x, 2=y, 3=z}
4. >>> map[1]="a"
5. >>> map
6. {1=a, 2=y, 3=z}
另外,如果Map中有重复的key键,后面的会直接覆盖掉前面的:
1. >>> val map = mutableMapOf(1 to "x", 2 to "y", 1 to "z")
2. >>> map
3. {1=z, 2=y}
后面的1 to "z"直接把前面的1 to "x"覆盖掉了。
hashMapOf(): HashMap<K, V>
创建HashMap对象。Kotlin直接使用的是Java的HashMap。
1. >>> val map: HashMap<Int, String> = hashMapOf(1 to "x", 2 to "y", 3 to "z")
2. >>> map
3. {1=x, 2=y, 3=z}
linkedMapOf(): LinkedHashMap<K, V>
创建空对象LinkedHashMap。直接使用的是Java中的LinkedHashMap。
1. >>> val map: LinkedHashMap<Int, String> = linkedMapOf()
2. >>> map
3. {}
4. >>> map[1]="x"
5. >>> map
6. {1=x}
linkedMapOf(vararg pairs: Pair<K, V>): LinkedHashMap<K, V>
创建带二元组Pair元素的LinkedHashMap对象。直接使用的是Java中的LinkedHashMap。
1. >>> val map: LinkedHashMap<Int, String> = linkedMapOf(1 to "x", 2 to "y", 3 to "z")
2. >>> map
3. {1=x, 2=y, 3=z}
4. >>> map[1]="a"
5. >>> map
6. {1=a, 2=y, 3=z}
sortedMapOf(vararg pairs: Pair<K, V>): SortedMap<K, V>
创建一个根据Key升序排序好的TreeMap。对应的是使用Java中的SortedMap。
1. >>> val map = sortedMapOf(Pair("c", 3), Pair("b", 2), Pair("d", 1))
2. >>> map
3. {b=2, c=3, d=1}
5.5.3 访问Map的元素
entries属性
我们可以直接访问entries属性
1. val entries: Set<Entry<K, V>>
获取该Map中的所有键/值对的Set。这个Entry类型定义如下:
1. public interface Entry<out K, out V> {
2. public val key: K
3. public val value: V
4. }
代码示例
1. >>> val map = mapOf("x" to 1, "y" to 2, "z" to 3)
2. >>> map
3. {x=1, y=2, z=3}
4. >>> map.entries
5. [x=1, y=2, z=3]
这样,我们就可以遍历这个Entry的Set了:
1. >>> map.entries.forEach({println("key="+ it.key + " value=" + it.value)})
2. key=x value=1
3. key=y value=2
4. key=z value=3
keys属性
访问keys属性:
1. val keys: Set<K>
获取Map中的所有键的Set。
1. >>> map.keys
2. [x, y, z]
values属性
访问val values: Collection<V>获取Map中的所有值的Collection。这个值的集合可能包含重复值。
1. >>> map.values
2. [1, 2, 3]
size属性
访问val size: Int获取map键/值对的数目。
1. >>> map.size
2. 3
get(key: K)
我们使用get函数来通过key来获取value的值。
1. operator fun get(key: K): V?
对应的操作符是[]:
1. >>> map["x"]
2. 1
3. >>> map.get("x")
4. 1
如果这个key不在Map中,就返回null。
1. >>> map["k"]
2. null
如果不想返回null,可以使用getOrDefault函数
1. getOrDefault(key: K, defaultValue: @UnsafeVariance V): V
当为null时,不返回null,而是返回设置的一个默认值:
1. >>> map.getOrDefault("k",0)
2. 0
这个默认值的类型,要和V对应。类型不匹配会报错:
1. >>> map.getOrDefault("k","a")
2. error: type mismatch: inferred type is String but Int was expected
3. map.getOrDefault("k","a")
4. ^
5.5.4 Map操作符函数
containsKey(key: K): Boolean
是否包含该key。
1. >>> val map = mapOf("x" to 1, "y" to 2, "z" to 3)
2. >>> map.containsKey("x")
3. true
4. >>> map.containsKey("j")
5. false
containsValue(value: V): Boolean
是否包含该value。
1. >>> val map = mapOf("x" to 1, "y" to 2, "z" to 3)
2. >>> map.containsValue(2)
3. true
4. >>> map.containsValue(20)
5. false
component1() component2()
Map.Entry<K, V>的操作符函数,分别用来直接访问key和value。
1. >>> val map = mapOf("x" to 1, "y" to 2, "z" to 3)
2. >>> map.entries.forEach({println("key="+ it.component1() + " value=" + it.component2())})
3. key=x value=1
4. key=y value=2
5. key=z value=3
这两个函数的定义如下:
1. @kotlin.internal.InlineOnly
2. public inline operator fun <K, V> Map.Entry<K, V>.component1(): K = key
4. @kotlin.internal.InlineOnly
5. public inline operator fun <K, V> Map.Entry<K, V>.component2(): V = value
Map.Entry<K, V>.toPair(): Pair<K, V>
把Map的Entry转换为Pair。
1. >>> map.entries
2. [x=1, y=2, z=3]
3. >>> map.entries.forEach({println(it.toPair())})
4. (x, 1)
5. (y, 2)
6. (z, 3)
getOrElse(key: K, defaultValue: () -> V): V
通过key获取值,当没有值可以设置默认值。
1. >>> val map = mutableMapOf<String, Int?>()
2. >>> map.getOrElse("x", { 1 })
3. 1
4. >>> map["x"] = 3
5. >>> map.getOrElse("x", { 1 })
6. 3
getValue(key: K): V
当Map中不存在这个key,调用get函数,如果不想返回null,直接抛出异常,可调用此方法。
1. val map = mutableMapOf<String, Int?>()
2. >>> map.get("v")
3. null
4. >>> map.getValue("v")
5. java.util.NoSuchElementException: Key v is missing in the map.
6. at kotlin.collections.MapsKt__MapWithDefaultKt.getOrImplicitDefaultNullable(MapWithDefault.kt:19)
7. at kotlin.collections.MapsKt__MapsKt.getValue(Maps.kt:252)
getOrPut(key: K, defaultValue: () -> V): V
如果不存在这个key,就添加这个key到Map中,对应的value是defaultValue。
1. >>> val map = mutableMapOf<String, Int?>()
2. >>> map.getOrPut("x", { 2 })
3. 2
4. >>> map
5. {x=2}
iterator(): Iterator<Map.Entry<K, V>>
这个函数返回的是 entries.iterator()。这样我们就可以像下面这样使用for循环来遍历Map:
1. >>> val map = mapOf("x" to 1, "y" to 2, "z" to 3 )
2. >>> for((k,v) in map){println("key=$k, value=$v")}
3. key=x, value=1
4. key=y, value=2
5. key=z, value=3
mapKeys(transform: (Map.Entry<K, V>) -> R): Map<R, V>
把Map的Key设置为通过转换函数transform映射之后的值。
1. >>> val map:Map<Int,String> = mapOf(1 to "a", 2 to "b", 3 to "c", -1 to "z")
2. >>> val mmap = map.mapKeys{it.key * 10}
3. >>> mmap
4. {10=a, 20=b, 30=c, -10=z}
注意,这里的it是Map的Entry。 如果不巧,有任意两个key通过映射之后相等了,那么后面的key将会覆盖掉前面的key。
1. >>> val mmap = map.mapKeys{it.key * it.key}
2. >>> mmap
3. {1=z, 4=b, 9=c}
我们可以看出,1 to "a"被-1 to "z"覆盖掉了。
mapValues(transform: (Map.Entry<K, V>) -> R): Map<K, R>
对应的这个函数是把Map的value设置为通过转换函数transform转换之后的新值。
1. >>> val map:Map<Int,String> = mapOf(1 to "a", 2 to "b", 3 to "c", -1 to "z")
2. >>> val mmap = map.mapValues({it.value + "$"})
3. >>> mmap
4. {1=a$, 2=b$, 3=c$, -1=z$}
filterKeys(predicate: (K) -> Boolean): Map<K, V>
返回过滤出满足key判断条件的元素组成的新Map。
1. >>> val map:Map<Int,String> = mapOf(1 to "a", 2 to "b", 3 to "c", -1 to "z")
2. >>> map.filterKeys({it>0})
3. {1=a, 2=b, 3=c}
注意,这里的it元素是Key。
filterValues(predicate: (V) -> Boolean): Map<K, V>
返回过滤出满足value判断条件的元素组成的新Map。
1. >>> val map:Map<Int,String> = mapOf(1 to "a", 2 to "b", 3 to "c", -1 to "z")
2. >>> map.filterValues({it>"b"})
3. {3=c, -1=z}
注意,这里的it元素是value。
filter(predicate: (Map.Entry<K, V>) -> Boolean): Map<K, V>
返回过滤出满足Entry判断条件的元素组成的新Map。
1. >>> val map:Map<Int,String> = mapOf(1 to "a", 2 to "b", 3 to "c", -1 to "z")
2. >>> map.filter({it.key>0 && it.value > "b"})
3. {3=c}
Iterable<Pair<K, V>>.toMap(destination: M): M
把持有Pair的Iterable集合转换为Map。
1. >>> val pairList = listOf(Pair(1,"a"),Pair(2,"b"),Pair(3,"c"))
2. >>> pairList
3. [(1, a), (2, b), (3, c)]
4. >>> pairList.toMap()
5. {1=a, 2=b, 3=c}
Map<out K, V>.toMutableMap(): MutableMap<K, V>
把一个只读的Map转换为可编辑的MutableMap。
1. >>> val map = mapOf(1 to "a", 2 to "b", 3 to "c", -1 to "z")
2. >>> map[1]="x"
3. error: unresolved reference. None of the following candidates is applicable ...
4. error: no set method providing array access
5. map[1]="x"
6. ^
8. >>> val mutableMap = map.toMutableMap()
9. >>> mutableMap
10. {1=a, 2=b, 3=c, -1=z}
11. >>> mutableMap[1]="x"
12. >>> mutableMap
13. {1=x, 2=b, 3=c, -1=z}
plus minus
Map的加法运算符函数如下:
1. operator fun <K, V> Map<out K, V>.plus(pair: Pair<K, V>): Map<K, V>
2. operator fun <K, V> Map<out K, V>.plus(pairs: Iterable<Pair<K, V>>): Map<K, V>
3. operator fun <K, V> Map<out K, V>.plus(pairs: Array<out Pair<K, V>>): Map<K, V>
4. operator fun <K, V> Map<out K, V>.plus(pairs: Sequence<Pair<K, V>>): Map<K, V>
5. operator fun <K, V> Map<out K, V>.plus(map: Map<out K, V>): Map<K, V>
代码示例:
1. >>> val map = mapOf(1 to "a", 2 to "b", 3 to "c", -1 to "z")
2. >>> map+Pair(10,"g")
3. {1=a, 2=b, 3=c, -1=z, 10=g}
4. >>> map + listOf(Pair(9,"s"),Pair(10,"w"))
5. {1=a, 2=b, 3=c, -1=z, 9=s, 10=w}
6. >>> map + arrayOf(Pair(9,"s"),Pair(10,"w"))
7. {1=a, 2=b, 3=c, -1=z, 9=s, 10=w}
8. >>> map + sequenceOf(Pair(9,"s"),Pair(10,"w"))
9. {1=a, 2=b, 3=c, -1=z, 9=s, 10=w}
10. >>> map + mapOf(9 to "s", 10 to "w")
11. {1=a, 2=b, 3=c, -1=z, 9=s, 10=w}
加并赋值函数:
1. inline operator fun <K, V> MutableMap<in K, in V>.plusAssign(pair: Pair<K, V>)
2. inline operator fun <K, V> MutableMap<in K, in V>.plusAssign(pairs: Iterable<Pair<K, V>>)
3. inline operator fun <K, V> MutableMap<in K, in V>.plusAssign(pairs: Array<out Pair<K, V>>)
4. inline operator fun <K, V> MutableMap<in K, in V>.plusAssign(pairs: Sequence<Pair<K, V>>)
5. inline operator fun <K, V> MutableMap<in K, in V>.plusAssign(map: Map<K, V>)
代码示例:
1. >>> val map = mutableMapOf(1 to "a", 2 to "b", 3 to "c", -1 to "z")
2. >>> map+=Pair(10,"g")
3. >>> map
4. {1=a, 2=b, 3=c, -1=z, 10=g}
5. >>> map += listOf(Pair(9,"s"),Pair(11,"w"))
6. >>> map
7. {1=a, 2=b, 3=c, -1=z, 10=g, 9=s, 11=w}
8. >>> map += mapOf(20 to "qq", 30 to "tt")
9. >>> map
10. {1=a, 2=b, 3=c, -1=z, 10=g, 9=s, 11=w, 20=qq, 30=tt}
减法跟加法类似。
put(key: K, value: V): V?
根据key设置元素的value。如果该key存在就更新value;不存在就添加,但是put的返回值是null。
1. >>> val map = mutableMapOf(1 to "a", 2 to "b", 3 to "c", -1 to "z")
2. >>> map
3. {1=a, 2=b, 3=c, -1=z}
4. >>> map.put(10,"q")
5. null
6. >>> map
7. {1=a, 2=b, 3=c, -1=z, 10=q}
8. >>> map.put(1,"f")
9. a
10. >>> map
11. {1=f, 2=b, 3=c, -1=z, 10=q}
putAll(from: Map<out K, V>): Unit
把一个Map全部添加到一个MutableMap中。
1. >>> val map = mutableMapOf(1 to "a", 2 to "b", 3 to "c", -1 to "z")
2. >>> val map2 = mapOf(99 to "aa", 100 to "bb")
3. >>> map.putAll(map2)
4. >>> map
5. {1=a, 2=b, 3=c, -1=z, 99=aa, 100=bb}
如果有key重复的,后面的值会覆盖掉前面的值:
1. >>> map
2. {1=a, 2=b, 3=c, -1=z, 99=aa, 100=bb}
3. >>> map.putAll(mapOf(1 to "www",2 to "tttt"))
4. >>> map
5. {1=www, 2=tttt, 3=c, -1=z, 99=aa, 100=bb}
MutableMap<out K, V>.remove(key: K): V?
根据键值key来删除元素。
1. >>> val map = mutableMapOf(1 to "a", 2 to "b", 3 to "c", -1 to "z")
2. >>> map.remove(-1)
3. z
4. >>> map
5. {1=a, 2=b, 3=c}
6. >>> map.remove(100)
7. null
8. >>> map
9. {1=a, 2=b, 3=c}
MutableMap<K, V>.clear(): Unit
清空MutableMap。
1. >>> val map = mutableMapOf(1 to "a", 2 to "b", 3 to "c", -1 to "z")
2. >>> map
3. {1=a, 2=b, 3=c, -1=z}
4. >>> map.clear()
5. >>> map
6. {}
