【Kotlin】Kotlin 中使用 Lambda 表达式替代对象表达式原理分析 ( 尾随 Lambda - Trailing Lambda 语法 | 接口对象表达式 = 接口#函数类型对象 )

文章详细介绍了Kotlin中的尾随Lambda语法,允许将Lambda表达式作为最后一个参数移出括号,提高代码可读性。同时,文章探讨了如何使用Lambda表达式替代对象表达式,特别是在处理只有一个函数的接口时,简化了匿名内部类的使用,以提高代码简洁度。通过示例分析了setOnClickListener函数的使用,展示了Lambda表达式的应用。
摘要由CSDN通过智能技术生成


我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=3e60fnr5m3uo0





一、尾随 Lambda - Trailing Lambda 语法



尾随 Lambda - Trailing Lambda 语法 : 满足如下两个条件 , 可以 使用 尾随 Lambda 语法 ;

  • 函数作为参数 ,
  • 并且 该函数参数 是最后一个参数 ,

那么可以 将最后一个参数 放在 括号外面 , 括号外使用 Lambda 表达式作为参数 ;

使用 尾随 Lambda 语法 可以使代码 更简洁 , 提高代码可读性 ;


示例说明 :

下面的函数 的最后一个参数 是 函数类型 ;

fun foo(x: Int, f: (Int) -> Int) {
    val result = f(x)
    println(result)
}

调用 foo 函数时 , 第二个参数是函数类型 , 并且该参数是函数的最后一个参数 ,

那么可以 使用 尾随 Lambda 语法 , 将 函数参数 移到括号外面 使用 Lambda 表达式表示 ;


正常调用方式如下 : 函数参数 放在 括号内进行传递 ;

foo(5, { x -> x * x })

使用 尾随 Lambda 语法 的调用方式 : 将第二个函数参数提取到括号外面 , 也就是将 Lambda 表达式 写在括号的外部 ;

foo(5) { 
	x -> x * x 
}




二、Kotlin 中使用 Lambda 表达式替代对象表达式原理




1、Lambda 替换对象表达式


在使用 Kotlin 开发时 , 经常遇到这种情况 , 最后一个函数是匿名内部类 , 匿名内部类中只实现了一个函数 , 此时使用 Lambda 表达式替代该 匿名内部类 ;

如 : 为按钮添加点击事件 , 对应的 Java 代码是

button.setOnClickListener(new View.OnClickListener() {
	@Override
	public void onClick(View view) {
		// 点击事件
	}
});

翻译成 Kotlin 代码后为 : 使用对象表达式

button.setOnClickListener(object : View.OnClickListener {
	override fun onClick(view: View) {
		// 点击事件
	}
})

更进一步简写为 :

button.setOnClickListener {
	// 点击事件
}

2、原理分析


Kotlin 中的 对象表达式 ,

object : View.OnClickListener {
	override fun onClick(view: View) {
		// 点击事件
	}
}

对应的就是 Java 中的 匿名内部类 ;

new View.OnClickListener() {
	@Override
	public void onClick(View view) {
		// 点击事件
	}
}

Lambda 表达式 其本质 就是 函数类型 的 匿名对象 , 也是一个实例对象 , 在堆内存中分配相应的空间 ;

在下面的代码中 , 使用 对象表达式 创建了匿名对象 , 该匿名类实现了 View.OnClickListener 接口 , 并实现了其中的 onClick 函数 ;

object : View.OnClickListener {
	override fun onClick(view: View) {
		// 点击事件
	}
}

符合以下两个条件 :

  • 函数 接收一个 接口类型 的匿名内部类 或 对象表达式 ;
  • 该 接口类型 中 只定义了一个函数 ;

可以 省略掉 匿名内部类 也就是 对象表达式的定义 , 直接使用 接口中的函数 类型对象 , 也就是 Lambda 表达式 / 匿名函数 / 闭包 来替代该 接口类型 变量 ;


3、示例分析


View 组件设置 按钮点击事件 的函数原型如下 : View#setOnClickListener 函数 接收一个 OnClickListener 实例对象作为参数 ;

    /**
     * 注册一个回调,以便在单击此视图时调用。如果这个视图是不可点击的,它就变成了可点击的。
     *
     * @param l 将运行的回调
     *
     * @see #setClickable(boolean)
     */
    public void setOnClickListener(@Nullable OnClickListener l) {
        if (!isClickable()) {
            setClickable(true);
        }
        getListenerInfo().mOnClickListener = l;
    }

OnClickListener 是一个接口 , 接口中只有一个方法 ;

    /**
     * 在单击视图时调用回调的接口定义。
     */
    public interface OnClickListener {
        /**
         * 当视图被单击时调用。
         *
         * @param v 被单击的视图。
         */
        void onClick(View v);
    }

下面是 IntelliJ IDEA 中 , 为 View 组件设置 点击事件 时 , 输入 setOnClickListener 出现的代码提示 ;

在这里插入图片描述


View#setOnClickListener 可以设置两种参数 :

  • OnClickListener 类型的对象表达式 :
        // 添加按钮点击事件 , 设置一个 对象表达式 表示 OnClickListener 子类
        // 作为点击事件
        textView.setOnClickListener(object : OnClickListener{
            override fun onClick(v: View?) {
                Log.i("TAG", "按钮点击事件")
            }
        })
  • OnClickListener#onClick 函数类型的 Lambda 表达式 :
        // 添加按钮点击事件 , 设置一个 OnClickListener#onClick 函数类型的 Lambda 表达式
        // 作为点击事件
        textView.setOnClickListener {
            Log.i("TAG", "按钮点击事件")
        }

如果设置了 OnClickListener#onClick 函数类型的 Lambda 表达式 , 其 Lambda 表达式类型为

(View) -> Unit

传入 View 类型实例对象 , 返回值为 void , 对应的就是 OnClickListener 接口中的 void onClick(View v); 函数类型 ;


如果 在 setOnClickListener 函数中设置了 (View) -> Unit 类型的 Lambda 表达式 ,

Kotlin 编译时会查找 setOnClickListener 函数真正接收的是 OnClickListener 接口实例对象 ,

传入一个 Lambda 表达式 , 会自动为其创建 OnClickListener 接口对应的匿名内部类 ,

并且将该 Lambda 表达式作为该匿名内部类的函数实体 ;


如果 传入的 Lambda 表达式类型 , 不符合 接口中的唯一的函数类型 ,

也就是再该示例中 Lambda 表达式类型不是 (View) -> Unit 类型的 , 就会在编译时报错 ,

报错信息如下 :

  • 返回值设置错误 : 设置错误的返回值 , 会提示
	'return' is not allowed here

在这里插入图片描述

  • 参数设置错误 : 默认参数是 it:View! , 如果设置成 it:String , 就会报如下错误 ;
Type mismatch.
Required:
((View!) → Unit)?
Found:
(String) → Unit
Expected parameter of type View!

在这里插入图片描述

评论 23
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值