前言
lambda表达式在java和kotlin中都有运用。方便开发者扩展一些自己的工具集,以及增加自己的开发效率。
函数类型
kotlin
(参数类型,参数类型...) -> 返回值类型
函数默认返回值类型Unit
,声明一个函数类型时,如果函数类型没有确切的返回值类型需要显示的指明为Unit
。
kotlin
// 无参数,没有确切返回值类型,返回Unit
() -> Unit
// 有两个参数,返回String
(Int,String) -> String
声明一个函数类型为可空时?
,需要将函数类型用()括起来,在()后面加?
kotlin
// 函数类型可空
(() -> Unit)?
// 函数类型可空
((Int,String) -> String)?
kotlin
// 延迟初始化,无需初始化值
lateinit var block:()->Unit
// 可空函数类型
var block1:(()->Unit)?=null
// 普通函数类型初始化
var block2:(()->Unit)={}
属性类型和函数类型的声明语法上是一样的。
Lambda表达式
kotlin
{参数名:参数类型,参数名:参数类型 -> 函数体}
Lambda表达式用花括号{}括起来的一段代码。->左边是Lambda表达式的参数列表,->右边是函数体。Lambda最后一行代码是这个Lambda的返回值。和if
when
表达式最后一行代码返回值类似。 用Lambda表达式完成对函数类型的初始化:
kotlin
val block:(Int,String) ->String = {a:Int,b:String -> "$a $b"}
用=来连接函数类型和Lambda表达式。 Kotlin编译器可以推断出该函数类型,我们可以在声明中省略它:
kotlin
val block={a:Int,b:String -> "$a $b"}
Lambda语法定义格式:
kotlin
{参数名:参数类型,参数名:参数类型 -> 函数体}
当函数类型有且只有一个参数类型时,初始化这个函数,可以在Lambda表达式的花括号中省略单个参数的声明和->。该参数将被隐式的声明为it。
kotlin
val block:(String) -> Unit = { println(it) }
也可以不使用隐式名称it,按照语法定义编写一个Lambda表达式
kotlin
val block:(String) ->Unit = {name:String -> println(name) }
函数类型实例调用
kotlin
val block:(String) -> Unit = { println(it) }
fun test() {
block("kotlin")
}
函数类型实例的调用和普通函数调用没有什么区别,在函数名后跟小括号()。在()中传入在声明时的参数即可。 可以使用funName.invoke()调用一个函数类型的实例。invoke方法是调用操作符()的重载。 kotlin.jvm.functions.Functions.kt文件中 Function2中:
kotlin
public interface Function2<in P1, in P2, out R> : kotlin.Function<R> {
public abstract operator fun invoke(p1: P1, p2: P2): R
}
调用一个函数类型的实例有两种方式:
kotlin
block("kotlin")和block.invoke("kotlin") 都可以完成对函数类型实例block的调用
高阶函数
高阶函数:将函数用作参数或返回值的函数。一个函数拥有函数类型的参数,或它的返回值类型是函数类型。
kotlin
fun test() {
val left = 1
val right = 2
val block = {left:Int,right:Int -> left+right}
val result = sum(left,right,block)
println(result)
}
fun sum(left:Int,right:Int,block:(Int,Int)->Int):Int{
return block.invoke(left,right)
}
通过类型实例block调用完成两个Int类型的值求和。通常对一个高阶函数的调用更习惯于用匿名Lambda表达式,匿名Lambda表达式和Java中匿名类如出一辙。java中用关键字new
创建一个匿名类,Kotlin中省略了创建对象的关键字。
kotlin
fun test() {
val left = 1
val right = 2
val result = sum(left,right,{left: Int, right: Int -> left + right})
println(result)
}
fun sum(left:Int,right:Int,block:(Int,Int)->Int):Int{
return block.invoke(left,right)
}
拖尾Lambda表达式
如果最后一个参数是函数,那么作为相应的参数传入的lambda表达式可以放到圆括号之外
kotlin
fun test() {
val left = 1
val right = 2
val result = sum(left,right) { left: Int, right: Int -> left + right }
println(result)
}
fun sum(left:Int,right:Int,block:(Int,Int)->Int):Int{
return block.invoke(left,right)
}
如果高阶函数只有一个函数类型的参数,在调用时可以省略(),直接在函数名后加花括号{}
kotlin
fun test() {
n{ println("n call") }
}
fun n(block:()->Unit){
block.invoke()
}
带上下文作用域Lambda表达式
A.(B)->C。在A类中定义了一个(B)->C的函数类型
kotlin
fun test() {
val lan = "kotlin"
lan.info()
}
val info:String.() -> Unit = {
val length = this.length
val isEmpty = this.isEmpty()
val hashCode = hashCode()
println("len=$length isEmpty=$isEmpty hashCode=$hashCode")
}
给String类定义了"扩展函数类型"的属性info,输出当前字符串信息。并使用Lambda表达式进行了初始化。花括号中直接使用隐式的this来访问当前接受者。 可以在Lambda的{}中像接受者的内部一样,访问接受者任意公开的方法和属性。
拥有函数返回值的函数
kotlin
fun test() {
val left = 1
val right = 2
val result = sum().invoke(left,right)
println(result)
}
fun sum():(Int,Int)->Int{
val block ={left:Int,right:Int -> left+right}
return block
}
sum函数返回的是一个函数类型:(Int,Int)->Int的实例,一个匿名Lambda表达式。执行函数类型中函数体的代码,需要对这个函数类型实例再进行一次调用
kotlin
val result = sum().invoke(left,right)
// 或者
val result2 = sum()(left,right)
官方源码中Suspend.kt提供了suspend
kotlin
public inline fun <R> suspend(noinline block: suspend () -> R): suspend () -> R = block
suspend
关键字修饰的函数或函数类型的参数称挂起函数,一般在协程中用到。
函数式接口
只有一个抽象方法的接口,或单一抽象方法接口
java
public interface OnClickListener{
void onClick(View v);
}
java中给一个view设置点击事件,会new
关键字创建匿名类
java
view.setOnclickListener(new View.OnClickListener(){
@Override
public void onClick(View v){...}
});
Kotlin中创建一个匿名类使用关键字object
kotlin
view.setOnClickListener(object:View.OnClickListener){
override fun onClick(v:View){...}
}
可以转换成函数类型(View) -> Unit
kotlin
// java接口
public interface OnClickListener{
void onClick(View v);
}
// kotlin函数类型
(View) -> Unit
kotlin
// java匿名类
new View.OnClickListener(){
@Override
public void onClick(View v){}
}
// kotlin Lambda表达式
{view:View-> }
简化上面点击事件
kotlin
view.setOnClickListener({view:View -> println("click")})
Lambda表达式该方法唯一参数,可以省略(),将花括号直接放到方法名后。
kotlin
view.setOnClickListener{ view:View -> println("click")}
函数类型只有一个参数,可以在Lambda表达式中省略参数和声明->。参数隐式声明为it
kotlin
view.setOnClickListener{println(it)}
实现自己的let方法
可以实现标准库Standard.kt中的一些高阶函数。let
函数可以让任意对象在任意地方调用。let函数首先定义一个泛型函数且是一个扩展函数,可以在任意地方调用,let函数一定是顶层函数
kotlin
fun <T> T.let(){}
let函数是一个拥有函数类型的参数
kotlin
fun <T> T.let(block:()->Unit){}
Lambda表达式获取调用者的隐式名it。let函数中拥有一个自己的参数,参数是调用者自己。
kotlin
fun <T> T.let(block:(T)->Unit){}
标注看Standard.kt中还有apply
also
with
函数
总结
Kotlin一些简化写法一般会在函数中出现,方便扩展一些自己常用的一些工具集。