Kotlin中的高阶函数
基本概念
kotlin中的函数比java中的函数高级,它可以作为参数进行传递, 也可以作为返回值返回
fun main(args: Array<String>) { args.forEach(::println)}
这个函数之所以能运行,是由于forEach中的参数是action: (T) -> Unit),一个参数T返回Unit的函数
public inline fun <T> Array<out T>.forEach(action: (T) -> Unit): Unit { for (element in this) action(element)}
而println刚符合这个条件
public inline fun println(message: Any?) { System.out.println(message)}
::println是一个包级函数的引用,下面我们看一个示例:
定义一个
class Hello{ fun world(){ println("Hello World") }}
可以赋值
val hello = Hello::world
下面再来看看
args.filter(String::isNotEmpty)
过滤掉非空的字符串,filter的实现如下
public inline fun <T> Array<out T>.filter(predicate: (T) -> Boolean): List<T> { return filterTo(ArrayList<T>(), predicate)}
参数为predicate: (T) -> Boolean,但是isNotEmpty并没有参数
@kotlin.internal.InlineOnlypublic inline fun CharSequence.isNotEmpty(): Boolean = length > 0
这是由于包级函数,有一个默认的参数就是它类本身,如上面isNotEmpty有一个默认的参数就是
CharSequence.
接下来我们再定义一个类
class PdfPrinter{ fun println(any: Any){ kotlin.io.println(any) }}下面这样引用是不行的fun main(args: Array<String>) { args.forEach(PdfPrinter::println)}
起因就是之前提到的,有一个默认的参数就是它类本身,就是PdfPrinter,假如我们去实例化对象调用是可以的
fun main(args: Array<String>) { val pdfPrinter = PdfPrinter() args.forEach(pdfPrinter::println)}
常见的高阶函数
map
下面我们做一个集合的映射,通常我们做法是这样.
fun main(args: Array<String>) { val list = listOf(1,3,4,5,10,8,2) val newList = ArrayList<Int>() list.forEach { val element = it * 2 + 3 newList.add(element) } newList.forEach (::println)}
而后使用高阶函数map去做会简单很多
fun main(args: Array<String>) { val list = listOf(1,3,4,5,10,8,2) val newList = list.map { it*2+3 } newList.forEach (::println)}
flatMap
fun main(args: Array<String>) { val list = listOf(1..20, 2..5, 100..322) val flatList = list.flatMap { it.map { "No.$it" } } flatList.forEach(::println)}
假如觉得it参数过多,难于了解可以加入参数名
fun main(args: Array<String>) { val list = listOf(1..20, 2..5, 100..322) val flatList = list.flatMap { intRange -> intRange.map { intElement -> "No.$intElement" } } flatList.forEach(::println)}
这样更加容易了解.
reduce
迭代求和
println(flatList.reduce{ acc,i -> acc+i})
求阶乘
fun factorial(n : Int):Int{ if (n == 0) return 1 return (1..n).reduce(){acc, i -> acc * i }}
(0..6).map(::factorial).forEach(::println)
fold
这个函数和reduce相似,不过它可以设置一个初始值
接着上面的函数累计求和(它有一个初始值5)
(0..6).map(::factorial).fold(5){acc, i -> acc+i }
另外我们还可以使用fold做字符串的连接
(0..6).map(::factorial).fold(StringBuilder()){ acc, i -> acc.append(i).append(",") }
joinToString
这个函数也是用来做字符串的连接
(0..6).joinToString(",")
filter
过滤基数
val result = (0..6).map(::factorial).filter { it % 2 == 1}
filter函数还有少量其它版本,例如filterIndexed
(0..6).map(::factorial).filterIndexed {index , i-> index%2 == 1}
求基数位的结果.
takeWhile
遇到第一个不符合条件的就结束,留下前边的作为一个新的集合返回.
(0..6).map(::factorial).takeWhile { it % 2 == 0 }
这个表示没有取到偶数的时候就结束提取.
let
接下来我们定义一个Worker
data class Worker(val name : String, val age : Int)
再定义一个findWorker
fun findWorker():Worker?{ return null}
fun main(args: Array<String>) { val worker = findWorker() println(worker?.name) println(worker?.age)}
我们去打印worker的name和age,这种打印方法每次都需要加入?判断能否为null,我们可以利用let函数使其更加简洁.
fun main(args: Array<String>) { findWorker()?.let { worker -> println(worker.name) println(worker.age) }}
由于Worker是data class我们还可以用下面来表示
findWorker()?.let { (name,age) -> println(name) println(age) }
定义函数的调用也是可以的
findWorker()?.let { worker -> worker.work()}
apply
使用apply可以使得上面的表达式更加简洁
fun main(args: Array<String>) { findWorker()?.apply { work() println(age) }}
with
与apply相似,不过with是调用.
fun main(args: Array<String>) { val br = BufferedReader(FileReader("hello.txt")) with(br){ var line : String? while (true){ line = readLine()?:break println(line) } close() }}
use
使用use调用使得上面表示更加简洁
BufferedReader(FileReader("hello.txt")).use { var line : String? while (true){ line = it.readLine()?:break println(line) }}
伪递归优化
data class ListNode(val value : Int, var next: ListNode?)
定义一个函数查找特定的节点
fun findListNode(head : ListNode?, value: Int):ListNode?{ head?:return null if (head.value == value) return head return findListNode(head.next,value)}
当我们return的时候调用的是函数本身,这种情况我们就叫做尾递归.
我们定义一个阶乘的算法
fun factorial(n : Long) : Long{ return n* factorial(n - 1)}
由于返回n* factorial(n – 1),这里有个n,并不是函数本身,这就不是尾递归.
假如我们想要优化尾递归,使其变为迭代可以加上关键字tailrec.
tailrec fun findListNode(head : ListNode?, value: Int):ListNode?{ head?:return null if (head.value == value) return head return findListNode(head.next,value)}
闭包
闭包的定义:
- 函数的运行环境
- 持有函数的运行状态
- 函数内部可以定义函数
- 函数内部可以定义类
下面定义一个函数
fun makeFun():()->Unit{ var count = 0 return fun(){ println(++count) }}
而后进行调用
fun main(args:Array<String>){ val x = makeFun() x() x() x() x() x()}
打印的值是
12345
这种情况函数嵌套函数并且保存变量count的情况就叫做闭包.
函数复合
下面我们定义
val add5 = {i : Int -> i + 5}val multiplyBy2 = {i : Int -> i * 2}fun main(args:Array<String>){ println(multiplyBy2(add5(8)))}
我们可以写一个函数去转换这种调用
infix fun <P1,P2,R> Function1 <P1,P2>.andThen(function: Function1<P2,R>) : Function1<P1,R>{ return fun(p1 : P1):R{ return function.invoke(this.invoke(p1)) }}fun main(args:Array<String>){ val add5AndMultiplyBy2 = add5 andThen multiplyBy2 println(add5AndMultiplyBy2(8))}
这就叫函数复合.
柯里化
柯里化用来拆分函数
fun log(tag : String,target: OutputStream, message: Any?){ target.write("[$tag]$message\n".toByteArray())}
科里化后的结果
fun log(tag : String) = fun(target : OutputStream) = fun(message : Any?) = target.write("[$tag]$message\n".toByteArray())
fun main(args: Array<String>) { log("benny",System.out,"HelloWorld") log("benny")(System.out)("HelloWorld Again")}
调用后结果相同
最后
在这里我总结出了互联网公司Android程序员面试涉及到的绝大部分面试题及答案做成了文档和架构视频资料免费分享给大家【包括高级UI、性能优化、架构师课程、NDK、Kotlin、混合式开发(ReactNative+Weex)、Flutter等架构技术资料】,希望能帮助到您面试前的复习且找到一个好的工作,也节省大家在网上搜索资料的时间来学习。
资料获取方式:加入Android架构交流QQ群聊:513088520 ,进群即领取资料!!!
点击链接加入群聊【Android移动架构总群】:加入群聊
资料大全
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » Kotlin中的高阶函数