高阶函数是将函数作为参数或者返回值的函数。
特点
举个
var onClick:()->Util //onClick变量类型为:无参且无返回类型的函数
var onClick:(A,B)->C //onCick变量类型为:参数类型分别为A,B,返回类型为C的函数
(x:Int,y:Int) //函数类型可以选择性包含函数的参数名,用于表明参数含义
((Int,Int)->Util)? //如果函数类型可为空,要使用圆括号后加?
上述就是一个高阶函数用法,定义某个变量的类型为函数,
注意:
()
Unit
返回类型不可省略函数类型实例调用
函数类型的值可以通过其invoke(...)
操作符调用:f.invoke(x)
或者直接f(x)
简述
—>
之前声明(参数类型可以省略),—>
后面。限定的返回
语法显示返回一个值)语法
val sum:(Int,Int)->Int={ x:Int,y:Int->x+y}
在 Kotlin 中有一个约定,如果函数的最后一个参数是一个函数,并且你传递一个 lambda 表达式作为相应的参数,你可以在圆括号之外指定它:
比如map函数
//map函数最后一个参数是一个函数
fun <T, R> List<T>.map(transform: (T) -> R): List<R> {
val result = arrayListOf<R>()
for (item in this)
result.add(transform(item))
return result
}
//使用
val dataList = list.map{it—>
it*2
}
在学习使用Kotlin高阶函数实现接口回调之前,先看看我们在Java中接口回调通常使用方法
普通使用
定义接口
public interface ICallback {
void nextFun(String message);
void errorFun(int code, String message);
}
业务中使用
public class LoginLogicImpl {
//声明login方法,参数为ICallback回调接口类型
public void login(ICallback callback) {
//TODO...
if (true) {
callback.nextFun("success");
} else {
callback.errorFun(404, "not found page");
}
}
}
外部调用(通过匿名内实现接口的回调)
public class LoginLogicPresenter {
LoginLogicImpl loginLogic = new LoginLogicImpl();
public void login() {
loginLogic = new LoginLogicImpl();
/**
*调用LoginLogicImpl的login方法,通过new ICallback()匿名类方式实现接口回调。
*必须显示声明所有接口中的回调方法。
*/
loginLogic.login(new ICallback() {
@Override
public void nextFun(String message) {
Log.d(TAG,"message->" + message)
}
@Override
public void errorFun(int code, String message) {
Log.e(TAG,"code->" + code + "message->" + message)
}
});
}
}
如上我们在使用该接口时候,需要显示的声明接口内所有的回调方法,如果不需要显示声明所有借口回调方法怎么办呢? 那么我们可以通过提供一个该接口的实现类来达到需求,具体实现如下
简单使用
声明接口的实现类
public class CallbackImpl implements ICallback {
@Override
public void nextFun(String message) {
}
@Override
public void errorFun(int code, String message) {
}
}
业务中使用
public class LoginLogicImpl {
//声明函数,参数为回调接口的实现类
public void register(CallbackImpl callbackImpl){
//TODO...
if(true){
callbackImpl.nextFun("success");
}else{
callbackImpl.errorFun(404,"not found page");
}
}
}
外部调用
public class LoginLogicPresenter {
LoginLogicImpl loginLogic = new LoginLogicImpl();
public void register() {
/**
*调用LoginLogicImpl的register方法,通过new CallbackImpl()匿名类
*实现回调(可选择性的显示声明接口内回调方法)
*/
loginLogic.register(new CallbackImpl() {
@Override
public void nextFun(String message) {
super.nextFun(message);
Log.d(TAG,"success->" + message);
}
//@Override 可根据需要选择性的显示回调方法
//public void errorFun(int code, String message) {
// super.errorFun(code, message);
//}
});
}
}
在kotlin中如果我们按照Java的思想进行接口开发使用,大概会有如下实现
Kotlin中接口普通使用
定义接口
interface ICallback {
fun nextFun(message: String)
fun errorFun(code: Int, message: String)
}
业务中使用
object LoginLogicImpl {
//声明login方法,参数为:ICallback回调接口类型
fun login( callback: ICallback) {
//todo...
if (true) {
callback.nextFun("success")
} else {
callback.errorFun(400, "failure...")
}
}
}
外部使用(使用object对象表达式
,类似于java中的匿名类
)
class LoginLogicPresenter {
fun login() {
/**
*调用LoginLogicImpl的login方法,使用object对象表达式实现接口回调(必须要显示声明接口中
*全部回调方法)
*/
LoginLogicImpl.login(object : ICallback {
override fun nextFun(message: String) {
println("success->$message")
}
override fun errorFun(code: Int, message: String) {
println("failure->$code,$message")
}
})
}
}
上面就是我们在kotlin中通过java思想实现的接口,使用了object对象表达式(类似Java中匿名类) 实现回调。
在我们使用Android系统提供的View的setOnClickListener
方法时候,我们发现其除了提供object
对象表达式方式之外,还提供了setOnClickListener(it->)
方法,如下
button.setOnClickListener(object :View.OnClickListener{
override fun onClick(v: View?) {
//TODO
}
})
button.setOnClickListener {it->
//TODO
}
可见后者并没有使用object
对象表达式,而是通过kotlin的高阶函数
和Lambda
表达式实现。那么我们是不是也可以将我们之前的接口更改为此种方式呢?当然可以!!如下:
使用Kotlin高级函数和Lambda优化接口回调
定义接口:声明回调函数
/**
*定义回调接口
*/
interface IResponseCallback<T> {
fun nextFun(data: T?)
fun errorFun(code: Int, message: String)
}
定义接口实现类:声明函数类型变量和对外提供的回调方法(与接口回调功能保持一致),并实现接口内回调方法
声明函数类型变量(参数与接口回调函数一致)
class ResponseCallbackListener<T> : IResponseCallback<T> {
//通过高阶函数声明函数类型变量(参数与接口互调函数一致)
lateinit var next: (data: T?) -> Unit
lateinit var error: (code: Int, message: String) -> Unit
}
声明回调方法(要与接口提供回调功能一致)
class ResponseCallbackListener<T> : IResponseCallback<T> {
//通过高阶函数声明函数类型变量(参数与接口互调函数一致)
lateinit var next: (data: T?) -> Unit
lateinit var error: (code: Int, message: String) -> Unit
//声明回调方法(与接口回调功能一致),参数为对应的函数类型变量
fun OnNext(nextListener: (data: T?) -> Unit) {
this.next = nextListener
}
fun OnError(errorListener: (code: Int, message: String) -> Unit) {
this.error = errorListener
}
}
实现接口内回调方法
class ResponseCallbackListener<T> : IResponseCallback<T> {
//通过高阶函数声明函数类型变量(参数与接口互调函数一致)
lateinit var next: (data: T?) -> Unit
lateinit var error: (code: Int, message: String) -> Unit
//声明回调方法(与接口回调功能一致),参数为对应的函数类型变量
fun OnNext(nextListener: (data: T?) -> Unit) {
this.next = nextListener
}
fun OnError(errorListener: (code: Int, message: String) -> Unit) {
this.error = errorListener
}
//实现接口内回调方法,调用对应函数变量的invoke(param)方法实现回调
override fun nextFun(data: T?) {
//函数类型的值可以通过其 invoke(……) 操作符调用:f.invoke(x) 或者直接 f(x)。
this.next.invoke(data)
//this.next(data)
}
override fun errorFun(code: Int, message: String) {
this.error.invoke(code, message)
}
}
使用
业务中使用
object LoginLogicImpl {
//声明register方法,参数为:函数类型
fun register(callback: CallbackListenerImpl.() -> Unit) {
var callBack = CallbackListenerImpl() //实例化回调接口实现类
callBack.callback() //将参数内的回调函数与实例化对象绑定
if (true) {
callBack.nextFun("success") //成功回调
} else {
callBack.errorFun(400, "failure...") //失败回调
}
}
}
外部调用
class LoginLogicPresenter {
fun register() {
//调用LoginLogicImpl的register方法(可选择性显示声明回调方法)
LoginLogicImpl.register {
OnNext {
println("OnNext->$it")
}
//OnError { code, message ->
// println("OnError->$code,$message")
//}
}
}
}
上面使用Kotlin的高阶函数以及Lambda表达式对普通的接口回调进行优化,并没使用object对象表达式
实现了接口回调,并且不需要显示声明接口提供的所有回调方法,而是选择性的声明所需的回调方法即可。
更多Kotlin高阶函数及Lambda表达式学习地址参见《Kotlin中文社区》