kotlin查漏补缺系列(3)——集合

179 阅读6分钟

kotlin查漏补缺系列(不定期更新)

前言

阅读本文需要你有一些java基础,至少已了解java集合的相关知识,耐心看完本文你将学会

  1. kotlin各种集合的使用
  2. kotlin集合和java集合的区别
  3. kotlin常用的集合操作符

有哪些集合类型

都知道java中集合主要包括三大类型,list,set以及map,在kotlin中也一样,集合的类图如下:

image.png

从这个类图,我们发现跟java相比,kotlin多了一些带Mutable前缀的接口或类,mutable是可变的意思, 很显然在kotlin中,集合被分成了两大类,可变集合和不可变集合,这也是kotlin与java的集合最大的不同

MutableList,MutableSet,MutableMap这些接口中提供了add,remove等方法,属于可变的集合接口

List,Set,Map这些接口中不提供任何关于写入操作的方法,而且从接口的泛型声明上也能看到,使用了out(对泛型不太理解的可以看看之前写过的一篇关于泛型的文章),也表明他是只读的,属于不可变的集合接口

public interface List<out E> : Collection<E>

kotlin的集合怎么用

kotlin对集合的使用封装了大量的库函数,使用起来方便很多

List

创建一个不可变的list用listOf,可变的用mutableListof

// 不可变集合
val list1 = listOf(1,2,3)
// 可变集合
val list2 = mutableListOf(1,2,3)

上述创建的list1是不可变的,只能读,而读又有两种方式

// 推荐用这种,更简洁
val a = list1[1]
val b = list1.get(1)

list2是可变的,可以添加,删除数据

val list2 = mutableListOf(1,2,3)
list2.add(1)
list2.removeAt(1)

上面提到了不可变的List接口在泛型声明上使用了out,所以List是支持协变的,也就是可以把类型为子类的List赋值给类型是父类的List

val list1 = listOf(1,2,3)
val list2 : List<Any> = list1

Map

跟创建list一样,创建map也都是类似的库函数

val map1 = mapOf("key1" to 1,"key2" to 2)
val map2 = mutableMapOf("key1" to 1,"key2" to 2)

创建不可变的Map用maoOf,可变的用mutableMapOf,这里面有一点比较特殊的语法,创建的时候直接传入了键值对,"key1" to 1这样的写法表示一个key-value,其中to是中缀表达式(这个以后讲解),作用就是构造出一个Pair类型的数据,而Pair存储的就是键值数据

对于Map的写操作和读操作也跟java有些不一样

val map1 = mapOf("key1" to 1,"key2" to 2)
val map2 = mutableMapOf<String,Int>()

// 取值kotlin推荐用[],当然也可以用get
val a = map1["key1"]
// 写值kotlin也推荐用[],当然也可以用put
map2["key3"] = 3

这里set就不展开说了,跟list几乎一样,只不过它里面的数据是没有顺序,且不能重复的

集合的转换

通过listOf,mapOf等创建出来的不可变集合都可以通过toMutablexxx 方法复制出一个可变的集合

// 原来的list1还是不可变的,复制的list3就是可变的
val list3 = list1.toMutableList()
list3.add(1)

集合的迭代

kotlin中,集合的迭代一般有三种方式,迭代器,for循环,foreach

迭代器

kotlin的集合同样是实现了Iterable接口的,所以可以通过iterator接口获取到一个迭代器然后用hasNext迭代

val list1 = listOf(1,2,3)

val iterator = list1.iterator()
while (iterator.hasNext()){
    println(iterator.next())
}

val map1 = mapOf("key1" to 1, "key2" to 2)

val iteratorMap = map1.iterator()
while (iteratorMap.hasNext()){
    println(iteratorMap.next().value)
}

for循环

val list1 = listOf(1, 2, 3)

for (i in list1) {
    println(i)
}

val map1 = mapOf("key1" to 1, "key2" to 2)

for (mapItem in map1) {
    println(mapItem.value)
}

forEach扩展函数

kotlin为集合封装了很多扩展函数(也就是下面要讲的操作符),其中foreach用来循环遍历,可传入一个lambda表达式,表达式有一个参数表示当前遍历到的元素

val list1 = listOf(1, 2, 3)

list1.forEach { 
    println(it)
}

val map1 = mapOf("key1" to 1, "key2" to 2)

map1.forEach {
    println(it.value)
}

集合的常用操作

kotlin的集合提供了非常多的操作符,需要的时候可以看看文档查一下,下面介绍下使用频率比较高的几个

元素操作符

例如获取元素,遍历元素

  • contains():是否包含某元素
  • first():获取第一个元素
  • first{}:可传入一个lambda,指定满足条件的第一个元素
  • last():获取最后一个元素
  • last{}:可传入一个lambda,指定满足条件的最后一个元素
  • forEach{}:遍历元素
  • forEachIndexed{}:遍历元素,相比foreach,可以拿到元素索引
val list = listOf(1,2,3)
val isExist = list.contains(1)
val first = list.first()
val first1 = list.first { it > 1 }
val last = list.last()
val last1 = list.last { it > 1 }
list.forEach {
    println(it)
}
list.forEachIndexed { index, item ->
    println("index is $index,item is $item")
}

映射操作符

映射就是可批量对集合的元素进行相同的操作

  • map{}:把每个元素按照特定逻辑进行转换,返回一个新的集合
  • flatmap{}:利用集合的每个元素,生成一个新的集合,最终把所有集合合并为一个,有点儿绕是不是,看看demo
  • group{}:对集合元素进行分组,返回一个Map,map中lambda的结果作为key,对应的item集合作为value

val list1 = listOf(1,2,3)
println(list1.map { it+1 })

// 运行结果
[2, 3, 4]



// flatmap
val list = listOf(listOf(1),listOf(2), listOf(3))
println(list)
// 其实可以直接用flatten实现这个效果,这个地方主要为了展示flatmap的作用
println(list.flatMap { it })

// 运行结果
[[1], [2], [3]]
[1, 2, 3]

//group
val list1 = listOf(1,2,3)
println(list1.groupBy { it>1 })

// 运行结果
{false=[1], true=[2, 3]}

过滤操作符

想取集合中部分子集的操作

  • filter{}:按照给定的条件过滤集合中的元素,并返回所有满足条件的元素组成的新集合
  • take():返回集合中前n个元素,同样的也有takeLast()
val list1 = listOf(1, 2, 3)
println(list1.filter { it > 1 })

// 运行结果
[2, 3]

println(list1.take(1))

// 运行结果
[1]

统计操作符

对集合中的元素按要求进行统计

  • maxorNull():获取集合中最大的元素,如果集合为空,返回null
  • any{}:判断集合是否存在元素满足条件
  • all{}:判断集合中是否所有元素都满足条件
val list1 = listOf(1,2,3)
println(list1.maxOrNull())
println(list1.any { it > 2 })
println(list1.sum())

// 运行结果
3
true
6

以上只是列取了相对常见的一些集合操作符号,实际上kotlin提供的集合操作符还有很多很多,基本能满足绝大部份的开发需要

koltin的数组与java的区别

因为数组也是用来存储批量的数据,跟集合有很多相同的使用场景,而kotlin的数组和java的数组在使用上也有些差距,这里简单提一下

kotlin数组是Array类型的,它是一个泛型类,我们也可以通过库函数arrayOf来创建一个数组

val array = arrayOf(1,2,3)

如果存储的元素类型是Int这些原生类型,为了避免装箱的开销,kotlin还提供了各种原生类型的数组,例如IntArray,ByteArray

val intArray = intArrayOf(1,2,3)
val byteArray = byteArrayOf(1,2,3)

另外kotlin的数组和集合之间是可以互转的

val array = arrayOf(1,2,3)
val list = listOf(1,2,3)
val list1 = array.toList()
val array1 = list.toIntArray()

以上就是kotlin集合基础相关的分享,感谢您的阅读,欢迎评论交流