作为一名前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"]},按名字首字母分组
到此,阁下该如何应对?
篇幅太长,下一章讲集合的过滤操作符、生产操作符及统计操作符。