什么是函数式编程
函数式编程是于面向对象编程范式相齐名的一种编程方式,主要依赖于高阶函数返回的数据,这些高阶函数专用于处理各种集合
,可方便的联合多个同类函数构建链式操作以创建复杂的计算行为。在Kotlin中支持多种编程范式,
有以下函数类别:
变换transform
、过滤filter
、合并combine
。
变换
变换是函数式编程的第一大类函数,变换函数会遍历集合内容,用一个以值参的形式传入的变换器函数,变换每一个元素,然后返回已包含修改数据的集合并可传给链上的其他函数。
Kotlin中常见的变换函数中有map和flatMap。
map
,会遍历接收者集合,让变换器函数作用于集合中的各个元素,返回结果是已修改元素的集合,可以作为链上下一个函数的输入。flatMap
,操作一个集合的集合,将多个集合的元素合并并返回一个包含所有元素的单一集合。
看个变换函数map的实例:
//1.变换函数map
private fun mapTest() {
val list = listOf<Int>(2, 5, 8, 10, 22)
//变换后的新列表
val newList = list.map {
it * 2 + 3
}
println("mapTest newList:$newList")
}
输出:mapTest newList:[7, 13, 19, 23, 47]
在来看个flatMap
的实例:
//2.变换函数flatMap
private fun flatMapTest() {
val list1 = listOf(1,2,3,4)
val list2 = listOf(7,8,9)
val newList = listOf(list1,list2).flatMap {
it
}
println("flatMapTest newList:$newList")
}
输出:flatMapTest newList:[1, 2, 3, 4, 7, 8, 9]
过滤
过滤
是Kotlin中函数式编程的第二大类函数,过滤函数接收一个predicate函数,该函数提供了一个查询条件用于查询集合中的元素并给出true或false的结果。如果predicate函数返回true
,则将元素添加到新的集合中,如果返回false
,则受检元素则移出新集合。
常用的过滤函数为:filter
。
以下为例子:
val list = listOf("I","like","kotlin")
val filterList = list.filter { it.contains("k") }
println("filterList : $filterList")
输出:filterList : [like, kotlin]
合并
合并
是Kotlin中函数式编程的第三大类函数,合并函数能将不同的集合合并成一个新的集合
。与接收者flatMap函数有不同。
Kotlin中常用的合并函数为:zip
和fold
。
zip
,合并函数来合并两个集合,并返回一个包含键值对的新集合。fold
,函数接收一个初始累加器值,随后会根据匿名函数的结果更新。
/**
* 合并函数 - zip,合并函数来合并两个集合,并返回一个包含键值对的新集合
*/
private fun zipTest(){
val list = listOf("a","b","c")
val listValue = listOf(28,30,33)
//合并后转成map
val zipMap = list.zip(listValue).toMap()
println("ZipTest : $zipMap")
println("zipList[\"a\"]=${zipMap["a"]}")
}
输出:
ZipTest : {a=28, b=30, c=33}
zipList[“a”]=28
fold
示例:
/**
* 合并函数 - fold,函数接收一个初始累加器值,随后会根据匿名函数的结果更新
*/
private fun foldTest(){
val list = listOf(1,2,3,4)
val foldValues = list.fold(0){acc, number ->
println("初始累计值:$acc")
acc + (number * 3)
}
println("foldValues : $foldValues")
}
输出:
初始累计值:0
初始累计值:3
初始累计值:9
初始累计值:18
foldValues : 30
序列
Kotlin内置的惰性集合叫序列
,序列不会索引排序它的内容,也不记录元素数目,事实上,在使用一个序列时,序列里的值可能有无限多,因为某个数据源能产生无限多个元素。
使用的序列为:generateSequence
,该函数接收一个初始种子值作为序列的起步值,在用generateSeuence
定义的序列调用函数时,generateSequence
会调用你指定的迭代器函数来决定下一个要产生的值。
下面以产生100个素数为例子:
fun main(){
val value = generateSequence(2){
it+1
}.filter { it.isPrime() }.take(100)
println("${value.count()}")
}
fun Int.isPrime():Boolean{
val ret = (2 until this).map {
this % it
}.none { it == 0 }
return ret
}
输出:100