-
Kotlin从入门进阶到实战
-
Kotlin是在java类库基础上进行了改造和扩展,引入了不可变集合类,同时扩展了大量方便实用的功能,这些功能api都在kotlin.collections包下。
-
在kotlin集合类中不仅能支持普通对象,而且能够持有函数类型的变量。
val funList: List<(Int) -> Boolean> = listOf({ it -> it % 2 == 0 }, { it -> it % 2 == 1 })
fun test() {
val list = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9)
val result = list.filter(funList[0])
val result1 = list.filter(funList[1])
println(result)
println(result1)
}
这就是面向对象式和函数式编程混合开发的样子
Kotlin集合类概述
- Kotlin集合类可以分为:可变集合类(Mutable)和不可变集合类(Immutable)。
- 常用的集合类主要有三种:List(列表)、Set(集)和Map(映射)
- List容器中的元素以线性方式存储,集合中可以存放重复对象。列表中的数据是有序排列
- Set集容器的元素无序、不重复。
- Map映射的持有的是 键值对 对象每一个对象都包含一堆 K-V对象。Map存储的容器中每一个对象都有一个Key对象,Key决定对象在容器中的位置。关键字Key是唯一的。关键字本身并不能决定对象的存储位置,它通过散列产生一个 散列码 的整数值,这个散列码对应值Value的存储位置。
- 如果从数据结构本身来看List中的下标就是Key,只不过key是有序的Int类型,所以说List也可以成为特殊的Map数据结构。而Set也是Key为Int值,但是Value不能重复。.
Kotlin集合类继承层次
- Iterable 父类任何类继承这个接口就表示可以遍历序列元素
- MutableIteIterable 在迭代器期间支持删除元素的迭代
- Collocation List和Set的父类接口,只可读不可变
- MutableCollection 支持添加和删除元素的Collection。它提供了写入的函数,如add、remove或clear等
- List 最常用的集合,继承Collection接口,元素有序,只读不可变
- MutableList 继承List,之处添加和删除元素,除了拥有List中读取的函数,还有add、remove或clear等写入数据的函数
- Set 元素无重复、无序。继承Collection接口。只读不可变
- MutableSet 继承Set,支持添加和删除元素Set
- Map 存储K-V对的集合,在Map映射表中Key是唯一的。
- MutableMap 支持添加和删除元素的Map
不可变集合类
- List列表分为只读不可变的List和可变MutableList。List列表的类型层次结构如下
- Set集合也分为不可变Set和可变MutableSet。Set集合类的类型层次如下
- Kotlin中Map和Set一样分为 只读Map和可变MutableMap。Map没有继承Collection接口。
创建集合类
-
Kotlin中分别用 listOf()、setOf()、mapOf() 创建不可变的容器,使用mutableListOf() 、mutableSetOf() 、mutableMapOf() 创建可变的Mutable容器
-
代码示例如下
val list = listOf(1, 2, 3, 4, 5)//创建不可变List
val mutableList = mutableListOf(1, 2, 3, 4, 5)//创建可变mutableList
val set = setOf(1,2,3,4,5)//创建不可变Set
val mutableSet = mutableSetOf(1,2,3,4,5)//创建可变mutableSet
val map = mapOf(1 to "A" , 2 to "B" ,3 to "C")//创建不可变Map
val mutableMap = mutableMapOf(1 to "A" , 2 to "B" ,3 to "C")//创建可变mutableMap
- 如果创建没有元素的空List使用ListOf()即可。不过需要显式指定变量的类型。否则会报错
Type inference failed: Not enough information to infer parameter T in inline fun <T> listOf( ): List<T> Please specify it explicitly.
val list = listOf<Int>()
val set = setOf<String>()
val map = mapOf<Int,String>()
遍历集合中的元素
- List、Set集合继承了Iterable接口,里面扩展了forEach函数来迭代遍历元素。同样Map接口也扩展了forEach函数迭代遍历元素。
val list = listOf<Int>(1, 2, 3, 4, 5, 6)
list.forEach { println(it) }
val set = setOf<String>("A", "B", "C")
set.forEach { println(it) }
val map = mapOf<Int, String>(1 to "o", 2 to "p", 3 to "q")
map.forEach { println("key = ${it.key} value = ${it.value}") }
在Iterable和Map中,forEach函数都是一个内联inline函数。另外如果我们想在迭代器遍历的时候获取index下标,在List和Set中可以使用下面的forEachIndexed函数
val list = listOf<Int>(1, 2, 3, 4, 5, 6)
//第一个参数是index 第二个参数 i 是value
list.forEachIndexed { index, i -> println("index = ${index} value = ${i}") }
val set = setOf<String>("A", "B", "C")
set.forEachIndexed { index, s -> println("index = ${index} value = ${s}") }
Map的元素是Entry类型,有entries属性持有
public val entries: Set<Map.Entry<K, V>>
这个Entry类型定义如下
public interface Entry<out K, out V> {
/**
* Returns the key of this key/value pair.
*/
public val key: K
/**
* Returns the value of this key/value pair.
*/
public val value: V
}
可以通过Entry属性获取Map所有键值对的Set
val map = mapOf(1 to "o", 2 to "p", 3 to "q")
map.entries.forEach { println("key = ${it.key} , value = ${it.value}") }
key = 1 , value = o
key = 2 , value = p
key = 3 , value = q
映射函数
- 使用map函数,可以把集合中的元素依次使用给定的转换函数进行映射操作,元素映射之后的新值会存入一个新的集合中,并且返回这个新集合。
- 在List、Set继承的Iterable接口和Map接口中,都提供了这个map函数。使用map的代码示例如下:
val list = listOf(1, 2, 3, 4, 5, 6)
val mapForList = list.map { it * it }// map函数对每个元素进行乘方操作
println(mapForList)
//输出结果如下
[1, 4, 9, 16, 25, 36]
val set = setOf("A", "B", "C")
val mapForSet = set.map { it + "helloMap" }//map函数对每个元素进行字符串拼接
println(mapForSet)
//输出结果如下
[AhelloMap, BhelloMap, ChelloMap]
val map = mapOf(1 to "o", 2 to "p", 3 to "q")
val mapForMap = map.map { it.value + "Map" }
println(mapForMap)
//输出结果如下
[oMap, pMap, qMap]
map函数如下:
public inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> {
return mapTo(ArrayList<R>(collectionSizeOrDefault(10)), transform)
}
这里的R类型是映射之后的数据类型,我们也可以传入一个List
val list = listOf(1, 2, 3, 4, 5, 6)
val mapFList = list.map { it -> listOf(it + 100, it + 1000, it + 10000) }
println(mapFList)
输出结果如下,每个元素映射为一个List,这个List中有三个元素 分别为 it + 100 it+1000 it+10000 ,这个时候返回值会是List套一个List
[[101, 1001, 10001], [102, 1002, 10002], [103, 1003, 10003], [104, 1004, 10004], [105, 1005, 10005], [106, 1006, 10006]]
Kotlin中还提供了一个flattern函数,效果是使结构变为一层还是上边的代码
val list = listOf(1, 2, 3, 4, 5, 6)
val mapFList = list.map { it -> listOf(it + 100, it + 1000, it + 10000) }.flatten()
println(mapFList)
输出如下
[101, 1001, 10001, 102, 1002, 10002, 103, 1003, 10003, 104, 1004, 10004, 105, 1005, 10005, 106, 1006, 10006]
flatMap函数是map和flat两个函数的复合逻辑,代码如下
val list = listOf(1, 2, 3, 4, 5, 6)
val mapFList = list.flatMap { it -> listOf(it + 1, it + 2) }
println(mapFList)
输出结果如下
[2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8]
过滤函数
- 使用filter()函数,下面是代码示例
data class Student(var name: String, var age: Int, var score: Int) {
override fun toString(): String {
return "$name ${age}岁 ${score}分"
}
}
@JvmStatic
fun main(args: Array<String>) {
val list = listOf(Student("张三", 18, 80)
, Student("小明", 16, 70)
, Student("小李", 16, 50)
, Student("小王", 20, 100)
, Student("小陆", 18, 59))
val filter = list.filter { it.score < 60 }
println(filter)
}
如果想找到成绩不及格的学生。使用 list.filter { it.score < 60 }
[小李 16岁 50分, 小陆 18岁 59分]
如果查看年龄>= 18岁的
val filter = list.filter { it.age >= 18 }
//输出结果如下
//[张三 18岁 80分, 小王 20岁 100分, 小陆 18岁 59分]
- 如果想通过下标来过滤,可以用filterIndexed
val filter = list.filterIndexed { index, student -> index % 2 == 0 && student.score > 55}
//输出 [张三 18岁 80分, 小陆 18岁 59分]
val filter = list.filterIndexed { index, student -> index % 2 == 0 && index > 3 }
//输出 [小陆 18岁 59分]
filterIndexed()函数如下
public inline fun <T> Iterable<T>.filterIndexed(predicate: (index: Int, T) -> Boolean): List<T> {
return filterIndexedTo(ArrayList<T>(), predicate)
}
排序函数
- Kotlin集合类的提供了倒叙排序的集合元素的函数reversed(),示例如下
@JvmStatic
fun main(args: Array<String>) {
val list = listOf(1, 2, 3)
val set = setOf(4, 5, 6)
println(list.reversed())
println(set.reversed())
}
打印输出如下
[3, 2, 1]
[6, 5, 4]
这个Iterable的扩展函数reversed()是直接调用的java.util.Collections.reverse()
public fun <T> Iterable<T>.reversed(): List<T> {
if (this is Collection && size <= 1) return toList()
val list = toMutableList()
list.reverse()//调用java中List类型的reverse()方法
return list
}
- 升序排列是用sorted()
@JvmStatic
fun main(args: Array<String>) {
val list = mutableListOf(3, 2, 1)
val set = setOf(6, 5, 4)
println(list.sorted())
println(set.sorted())
}
输出如下
[1, 2, 3]
[4, 5, 6]
sorted()也是直接调用了java api来实现的
public fun <T : Comparable<T>> Iterable<T>.sorted(): List<T> {
if (this is Collection) {
if (size <= 1) return this.toList()
@Suppress("UNCHECKED_CAST")
return (toTypedArray<Comparable<T>>() as Array<T>).apply { sort() }.asList()
}
return toMutableList().apply { sort() }
}
最终调用java.util.Arrays.sort()
public actual fun <T : Comparable<T>> MutableList<T>.sort(): Unit {
if (size > 1) java.util.Collections.sort(this)
}
元素去重
- distinct()
@JvmStatic
fun main(args: Array<String>) {
val list = listOf(1, 2, 3, 4, 2, 5, 6, 4, 3, 5, 3, 1, 9)
println(list.distinct())
}
打印输出
[1, 2, 3, 4, 5, 6, 9]
data class Student(var name: String, var age: Int, var score: Int) {
override fun toString(): String {
return "$name ${age}岁 ${score}分"
}
}
@JvmStatic
fun main(args: Array<String>) {
val list = listOf(Student("张", 10, 100)
, Student("张", 10, 100)
, Student("李", 20, 90))
println(list.distinct())
}
输出结果如下
[张 10岁 100分, 李 20岁 90分]