数组
方法 | 含义 |
---|---|
arrayOf | 创建一个指定类型的数组,数组中的元素就是函数的实参 |
arrayOfNulls | 创建一个指定大小的数组,默认时数组中的元素都为 null |
Array 构造函数 | 需要指定大小,并提供 lambda 表达式获取每一个元素 |
intArrayOf等 | 创建一个 int[] |
如:使用构造函数
fun main(args: Array<String>) {
val a = Array(26) { i ->
('a' + i).toString()
}
println(a.joinToString(separator = ",")) // a - z 所有的字母
}
lambda 得到的参数为当前下标,返回值是当前下标对应的元素。
使用 Array<> 创建的数组对应到 Java 中将是包装类的数组。而要使用基本数据类型的数组,需要使用 intArrayOf 、IntArray 类似的方法。
IntArray 与 Array<Int>
kt 中定义数组有两种方式:一种通过 IntArray,一种通过 Array<Int>。前者会转换成 int[],后者会转换成 Integer[]。
val b: IntArray = IntArray(2)
println(b[0]::class.java) // int
val a: Array<Int> = Array(2, { it })
println(a[0]::class.java) // java.lang.Integer
由于 Array<Int> 元素是一个对象,因此创建 Array<Int> 时,必须指定初始化元素的方法。
StringArray 与 Array<String>
前者是一个类,并不是一个数组;后组是 String[]:
val b: Array<String> = Array<String>(2, { it -> "$it" })
println(b::class.java) // class [Ljava.lang.String;
val a = StringArray()
println(a::class.java) // class com.sun.xml.internal.fastinfoset.util.StringArray
集合
kt 中没有自己的集合类库,全部采用的是 java 标准的集合类。
创建
集合类型 | 只读 | 可变 |
---|---|---|
List | listOf | mutableListOf、arrayListOf |
Set | setOf | mutableSetOf、hashSetOf、linkedSetOf、sortedSetOf |
Map | mapOf | mutableMapOf、hashMapOf、linkedMapOf、sortedMapOf |
下面的代码中的 javaClass 等价于 java 中的 getClass() 函数。
val list = arrayListOf("A","B")
list.add("aa")
println(list.javaClass) // java.util.ArrayList
val list2 = listOf<String>()
// list2 中没有 add / remove 方法,因为 listOf 返回的是一个只读的 List
println(list2.javaClass) // kotlin.collections.EmptyList
val set = hashSetOf("A","B")
println(set.javaClass) // java.util.HashSet
val map = hashMapOf<Int,String>()
println(map.javaClass) // java.util.HashMap
}
操作集合的 api
filter 与 map
函数 | 含义 |
---|---|
filter | 过滤掉集合中不需要的元素 |
map | 对每一个元素进行操作,并将结果存入新的集合 |
filterKeys | 操作 map,过滤掉返回 false 的键值对。参数为每一个 key |
filterValues | 操作 map,过滤掉返回 false 的键值对。参数为每一个 value |
mapKeys | 操作 map,对每一个 key 进行映射 |
mapValues | 操作 map,对每一个 value 进行映射 |
filterNotNull | 过滤掉集合中的 null 元素 |
fun main(args: Array<String>) {
val list = listOf(1, 2, 3, 4)
println(list.filter { it % 2 == 0 }) // [2, 4]
println(list.map { it * 2 }) // [2, 4, 6, 8]
val map = mapOf(1 to "s1", 2 to "s2")
println(map.filterKeys { it % 2 == 0 }) // {2=s2}
println(map.filterValues { it.contains("1") }) // {1=s1}
// 返回结果会当作新 key
println(map.mapKeys { it.key * 2 }) // {2=s1, 4=s2}
println(map.mapValues { "${it.value}--" }) // {1=s1--, 2=s2--}
}
filterNotNull 用于过滤一个集合中所有的 null 值,并将非 null 存储在一个新的集合中返回:
fun main(args:Array<String>){
// 声明一个元素可空的集合
val l = listOf(1,3,3,null,324,null,423)
val result = l.filterNotNull() // 其类型为 List<Int> ,其中元素不可能为 null
println(result.size)// 5 过滤掉所有的 null
}
判断
函数 | 含义 |
---|---|
all | 判断集合中是否所有元素都满足表达式 |
any | 判断集合中是否有元素满足表达式 |
count | 统计集合中有多少元素满足表达式 |
find | 找到第一个满足表达式的元素 |
firstOrNull | 同 find |
fun main(args: Array<String>) {
val list = listOf(1, 4, 3, 4,8)
println(list.all(::test)) // false
println(list.any(::test)) // true
println(list.count(::test)) // 3
println(list.find(::test)) // 4
println(list.firstOrNull(::test)) // 4
}
fun test(a:Int) = a % 2 == 0
groupBy
将所有元素按不同特征划分为不同的组。每一个分组都会存储在一个列表中,键为对应的特征。示例中会按元素是否为偶数进行分组。
fun main(args: Array<String>) {
val list = listOf(1, 4, 3, 4, 8)
println(list.groupBy(::test)) // {1=[1, 3], 0=[4, 4, 8]}
}
fun test(a: Int) = a % 2
flat 系列
flat 将多个列表合并成一个列表。
函数 | 含义 |
---|---|
flatMap | 首先对集合中的元素进行映射,将映射结果进行合并 |
flatten | 合并多个集合 |
所示代码中,第一个先将 books 映射成一个列表,然后将该列表合并。第二个是直接将一系列的列表合并成一个。
fun main(args: Array<String>) {
val b1 = Book("b1", listOf("ab11","ab12"))
val b2 = Book("b2", listOf("ab21","ab22"))
val b3 = Book("b3", listOf("ab31","ab32"))
val books = listOf(b1,b2,b3)
println(books.flatMap { it.authors }) // [ab11, ab12, ab21, ab22, ab31, ab32]
val ll = listOf(listOf("1","2"), listOf("232","fda"))
println(ll.flatten())//[1, 2, 232, fda]
}
class Book(val name:String,val authors:List<String>)
可变与不可变
kt 在设计接口时,将访问与修改接口分开了。Collection 只提供访问的 api ,而 MutableCollection 提供了修改的 api。
一般使用时,尽量使用不可变的集合;真要需要时,才使用可修改的。
序列
上述的每一个操作都会返回一个集合,所以当链式使用 filter ,map,flat 等操作时,会产生大量的中间集合。如果集合的数据特别大,则内存开销会非常大。而使用 序列不需要额外的开销。
初始化
有两种方式:
- 使用 asSequence 将任何集合转为序列,使用 toList 将任何序列转为集合。
2.使用 generateSequence 直接生成一个序列。该方法需要指定一个初始值,并提供一个由前一个元素生成下一个元素的表达式。
fun main(args: Array<String>) {
val s = generateSequence(0) { it+1 }
val r = s.takeWhile { it < 10 }
println(r.sum()) // 45
}
操作
序列的操作是惰性的:只有在获取结果的时候才会执行所有的操作,在中间不会执行任何操作
相较于序列,集合在每调用一个方法后会立即执行,并将下一个操作应用到得到的结果上。
fun main(args: Array<String>) {
val l = listOf(1, 2, 3, 4, 5)
// 该代码不会输出任何语句
l.asSequence().map { println(it);it * it }.filter { println("filter ${it}");it % 2 == 0 }
// 调用 asList 后才会有输出
l.asSequence().map { println("map ${it}");it * it }.filter { println("filter ${it}");it % 2 == 0 }.toList()
}
执行逻辑
序列中的所有操作是按顺序应用在每一个元素上:处理完第一个元素后,再处理第二个。因此,序列中有些元素根本不会发生任何变化,如果在轮到它之前就已经得到结果。
与集合比较
序列的操作是惰性的。因此,如果要处理的数据量比较大,可以使用序列,以节省内存。
序列的操作不是内联的,但集合的操作是内联的。因此,能用集合时尽量使用集合。