如果一个函数接收另一个函数作为参数,或者返回类型是一个函数,那么这个函数我们就称之为高阶函数。任何以lambda或者函数引用作为参数的函数,或者返回值为lambda或函数引用的函数,都是高阶函数。
在参数中使用高阶函数示例:
/**
* 加法
*/
fun add(a: Int, b: Int): Int {
return a + b
}
/**
* 减法
*/
fun minus(a: Int, b: Int): Int {
return a - b
}
/**
* 乘法
*/
fun cheng(a: Int, b: Int): Int {
return a * b
}
/**
* 运算
*
* operate:(Int, Int)->Int 表示定义的一个函数,将其作为calculate参数的形参,实际传的时候是传入add或minus函数
*/
fun calculate(a: Int, b: Int, operateType: (Int,Int) -> Int): Int {
return operateType(a, b)
}
测试:
Log.i("minfo", "" + calculate(12, 4, ::add))
Log.i("minfo", "" + calculate(12, 4, ::minus))
Log.i("minfo", "" + calculate(12, 4, ::cheng))
然后将add方法的变相写法:
/**
* 将函数作为变量
*/
val add1 = fun(a: Int, b: Int): Int {
return a + b
}
//直接返回结果
val add2 = fun(a: Int, b: Int) = a + b
//函数闭包写法
val add3 = {a: Int, b: Int->
a + b
}
val add4 = ::add
高阶函数作为返回值示例
//此方法的作用是如果type等于1,那么就从Num类中取出num进行乘法操作,如果不等于一,就进行相加操作
fun getNum(type: Int): (Num) -> Int {
if (type == 1) {
//这是一种写法
return { entity ->
entity.num * entity.num
}
} else {
//这是另一种简写,可以用it代替entity参数
return {
it.num + it.num
}
}
}
首先定义了一个高阶函数,他传入三个参数,两个Int型的值和一个函数类型的值,在方法内部调用“函数类型的值”,因为它本身是函数,所以可以直接调用,并且将前两个Int型作为形参传了进去。接下来我们定义了两个函数add和minus,这两个函数实现他们本身的逻辑,最后在main函数里面调用了此高阶函数,其中::add和::minus是固定写法,表示函数的引用。
自己实现kolin自带高阶函数:
inline fun <T> Iterable<T>.myFilter(predicate:(T) -> Boolean): List<T> {
var list = ArrayList<T>()
for (item in this) {
if (predicate(item)) {
list.add(item)
}
}
return list
}
inline fun <T> Iterable<T>.myForEach(handle:(T) -> Unit) {
for (item in this) {
handle(item)
}
}
inline fun <T> T.myApply(handle:(T)-> Unit): T {
handle(this)
return this
}
inline fun <T, R> myWith(t: T, use:(T)-> R): R {
return use(t)
}
inline fun <T, R> T.myRun(handle:(T) -> R): R {
return handle(this)
}
测试使用:
ArrayList<User>().myApply {
add(User("小王", 15))
add(User("小李", 22))
add(User("小张", 25))
}.myFilter({
it.age > 20
}).myForEach({
Log.i("minfo", it.name)
})
myWith(User("小王", 15)) {
name = "哈哈"
Log.i("minfo", name)
}
User("小王", 15).myRun {
name = "修改小王为小花"
Log.i("minfo", name)
}
参考
Kotlin高阶函数
lambda(高阶函数)转成Java是怎么样的
将如下高阶函数转成java
fun calculate(a: Int, b: Int, operateType: (Int,Int) -> Int): Int {
return operateType(a, b)
}
转如下代码:
public final int calculate(int a, int b, @NotNull Function2 operateType) {
Intrinsics.checkNotNullParameter(operateType, "operateType");
return ((Number)operateType.invoke(a, b)).intValue();
}
java中,则将高阶函数用了kotlin中一个接口Funtions来代替,接口仅有一个invoke方法,接口方法兼容了不同数量参数的高阶函数。
package kotlin.jvm.functions
/** A function that takes 0 arguments. */
public interface Function0<out R> : Function<R> {
/** Invokes the function. */
public operator fun invoke(): R
}
/** A function that takes 1 argument. */
public interface Function1<in P1, out R> : Function<R> {
/** Invokes the function with the specified argument. */
public operator fun invoke(p1: P1): R
}
/** A function that takes 2 arguments. */
public interface Function2<in P1, in P2, out R> : Function<R> {
/** Invokes the function with the specified arguments. */
public operator fun invoke(p1: P1, p2: P2): R
}
...
高阶函数有几个参数,就使用对应几个参数的那个接口替换,并在java代码中调用invoke方法。
java调用kotlin的高阶函数是怎么调的
在java中调用如下高阶函数
fun calculate(a: Int, b: Int, operateType: (Int,Int) -> Int): Int {
return operateType(a, b)
}
可以知道转为java之后函数参数变为了Functions类里面接口的类型,
public final int calculate(int a, int b, @NotNull Function2 operateType) {
Intrinsics.checkNotNullParameter(operateType, "operateType");
return ((Number)operateType.invoke(a, b)).intValue();
}
具体调用时,java调用需要传入Function接口类型参数,如这里是2个参数,传入Function2对象,需要自行实现invoke回调方法。如果该高阶函数只有一个参数,则这里是new Function1()
new LambdaUse().calculate(1, 2, new Function2<Integer, Integer, Integer>() {
@Override
public Integer invoke(Integer integer, Integer integer2) {
return null;
}
});
我理解的使用高阶函数的场景
在以前java里面需要将不确定的功能暴露给外部或者子类实现,可以使用接口或者抽象方法来调用,将实现交给外部。那么这个高阶函数就是实现同样功能的写法,用接口或者抽象方法来实现的地方,都可以改成高阶函数来做。
封装网络请求的例子就是一个很好的事例,如果不使用高阶函数,那么我们为了实现网络请求成功后的回调,还得额外多写一些接口类,得益于高阶函数,我们只需要这样即可:
/**
* 传入suspend方法发起请求,获取到BaseData数据,如果请求成功回调successCallBack函数并返回 T
* 如果失败,调用failCallBack函数自行实现处理
*/
fun <T: Any> requestData(
showLoading: Boolean = true,
request: suspend () -> BaseData<T>,
successCallBack: (T) -> Unit,
failCallBack: suspend (String) -> Unit = { errMsg->
showLoading()
}
) {
viewModelScope.launch {
if (showLoading) {
showLoading()
}
try {
val baseData = request.invoke()
if (baseData.isSuccess()) {
baseData.data?.let { successCallBack(it) }
} else {
baseData.errorMsg?.let { error(it) }
}
} catch (e: Exception) {
e.message?.let { failCallBack(it) }
} finally {
if (showLoading) {
showLoading()
}
}
}
}
调用请求处理:
fun loadData() {
requestData(
showLoading = true,
request = { getUser() },
successCallBack = { data ->
})
}
suspend fun getUser(): BaseData<User> {
return TODO("Provide the return value")
}