作为一名前Java开发者,当我每次需要写一些冗长且常用的功能时,时常会发出这样的感叹:
这个功能JDK中怎么没有啊?每次都要写好几十行代码,JDK不应该把这个功能封装一下吗
不知道广大的Java开发者是否也会跟我一样,也会有类似的感慨,欢迎大家留言讨论。
在用了Kotlin之后,才知道什么才是真正的方便,其针对集合做了非常丰富的支持:排序、查询、条件过滤、类型转换等等,本文就盘点一下Kotlin中集合的一些骚操作。
Kotlin 标准库提供了 set、list以及 map的实现。与 Java 不同的是,Kotlin对集合做了区分:元素是否可变,可变的容器会加Mutable前缀,实现对应的接口:
一个 只读 接口,只提供访问集合元素的操作。
一个 可变 接口,通过写操作扩展相应的只读接口:添加、删除及更新其元素。
Kotlin中Collection的结构如下:
每种容器类型都有可变与不可变之分,可变的是不可变的子类,如:
MutableCollection会实现对应的Collection接口(如下图)
集合的高阶操作大致可分为六类:
元素操作符
顺序操作符
映射操作符
过滤操作符
生产操作符
统计操作符
componentX() :获取集合中的某一个元素,其中的X只能取1..5,其是List的扩展函数
contains(element: T): 集合中是否包含指定的元素,若存在则返回true,反之返回false
elementAt(index: Int): 获取对应下标的元素。若下标越界,会抛出IndexOutOfBoundsException(下标越界)异常,与get(index)一样
elementAtOrElse(index: Int, defaultValue: (Int) -> T): 获取对应下标的元素。若下标越界,返回默认值,此默认值就是你传入的下标的运算值
elementAtOrNull(index) : 获取对应下标的元素。若下标越界,返回null
first() : 获取第一个元素,若集合为空集合,这会抛出NoSuchElementException异常
first{} : 获取满足条件的第一个元素。若不满足条件,则抛出NoSuchElementException异常
firstOrNull() : 获取第一个元素,若集合为空集合,返回null
firstOrNull{} : 获取满足条件的第一个元素。若不满足条件,返回null
getOrElse(index,{...}) : 同elementAtOrElse
getOrNull(index) : 同elementAtOrNull
last() : 与first()相反
last{} : 与first{}相反
lastOrNull{} : 与firstOrNull()相反
lastOrNull() : 与firstOrNull{}相反
indexOf(T) : 返回指定元素的下标,若不存在,则返回-1
indexOfFirst{...} : 返回第一个满足条件元素的下标,若不存在,则返回-1
indexOfLast{...} : 返回最后一个满足条件元素的下标,若不存在,则返回-1
single() : 若集合的长度等于0,则抛出NoSuchElementException异常,若等于1,则返回第一个元素。反之,则抛出IllegalArgumentException异常
single{} : 找到集合中所有满足条件的元素,若找到的元素个数为1,则返回该元素。否则会根据不同的条件,抛出异常(与singel()一致)
singleOrNull() : 与single()类似,但不会抛出异常,会返回null
singleOrNull{} : 与single{}类似,但不会抛出异常,会返回null
forEach{...} : 遍历元素本身
forEachIndexed{index,value} : 遍历下标及元素
看到这里,你是不是想说,Kotlin就这?
稍安勿躁!
接着往下看~
reversed() : 反转集合。
sorted() : 自然升序。
sortedBy{} : 有条件的升序(不满足条件的放在前面,满足条件的放在后面)
sortedDescending() : 自然降序。
sortedByDescending{} : 有条件的降序(不满足条件的放在后面,满足条件的放在前面),与sortedBy{}相反
sortedWith(comparator: Comparator``<``in T):自定义比较器
map{...} : 把每个元素按照特定的方法进行转换,组成一个新的集合
mapNotNull{...} : 与map{}函数的作用相同,但会过滤掉转换之后为null的元素
mapIndexed{index,result} : 与map{}函数的作用相似,但在转换过程中可以拿到每个元素的下标,最终也会组成一个新的集合
mapIndexedNotNull{index,result} : 与mapIndexed{}函数的作用相同,但会过滤掉转换之后为null的元素
<T, R> Iterable<T>.flatMap(transform: (T) -> Iterable<R>): List<R>: 可分为flat和map两个步骤,flat可以将集合扁平化处理,map可以对集合进行转换。该函数在处理集合嵌套层级很多的情况很实用,可以很大程度上简化操作
<T, K> Iterable<T>.groupBy(keySelector: (T) -> K): Map<K, List<T>>: 对集合进行分组。你需要传一个key,函数会根据条件把集合拆分为为一个Map<K,List<T>>类型的集合
示例:
`val numbers = listOf(1, 2, 3, 4) val squared = numbers.map { it * it } // squared 是 [1, 4, 9, 16],每个数字被平方 val mixedValues = listOf("1", "two", "3", "four") val integers = mixedValues.mapNotNull { it.toIntOrNull() } // integers 是 [1, 3],只有可以转换为整数的字符串被保留 val words = listOf("apple", "banana", "cherry") val indexedWords = words.mapIndexed { index, word -> "$index: $word" } // indexedWords 是 ["0: apple", "1: banana", "2: cherry"],每个单词前加上了它的索引 val data = listOf("some", "", "text", "none", "here") val nonEmptyItems = data.mapIndexedNotNull { _, value -> if (value.isNotBlank()) value else null } // nonEmptyItems 是 ["some", "text", "none", "here"],过滤掉了空字符串 val nestedLists = listOf(listOf(1, 2), listOf(3), listOf(4, 5, 6)) val flatList = nestedLists.flatMap { it } // flatList 是 [1, 2, 3, 4, 5, 6],将嵌套的列表展平 val people = listOf("Alice", "Bob", "Charlie", "David", "Eve") val byFirstLetter = people.groupBy { it.first() } // byFirstLetter 是 {'A'=["Alice"], 'B'=["Bob"], 'C'=["Charlie"], 'D'=["David"], 'E'=["Eve"]},按名字首字母分组 `
到此,阁下该如何应对?
篇幅太长,下一章讲集合的过滤操作符、生产操作符及统计操作符。