文章目录

  • 一、尾随 Lambda - Trailing Lambda 语法
  • 二、Kotlin 中使用 Lambda 表达式替代对象表达式原理
    • 1、Lambda 替换对象表达式
    • 2、原理分析
    • 3、示例分析

我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻: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() {@Overridepublic 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() {@Overridepublic 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!

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

  1. common-collections中Java反序列化漏洞导致的RCE原理分析

    2019独角兽企业重金招聘Python工程师标准>>> common-collections中Java反序列化漏洞导致的RCE原理分析 隐形人真忙 · 2015/11/11 22:4 ...

  2. List中subList方法抛出异常java.util.ConcurrentModificationException原理分析

    1.首先从测试代码开始: public class Test {public static void main(String[] args) {List<Integer> list = n ...

  3. Netty技术细节源码分析-Recycler对象池原理分析

    本文是该篇的修正版 本文的github地址:点此 该文所涉及的netty源码版本为4.1.6. Netty的对象池Recycler是什么 Recycler是Netty中基于ThreadLocal的轻量 ...

  4. java中的算数运算符号用法与原理分析

    一.表达式求值简单说明: 1.求值表达式主要包括加减乘除四种基本运算,其实表达式可以看做由一个个二元运算构成,前一个二元运算的结果作为后一个二元运算的输入. 举个例子: "1+2-4=&qu ...

  5. HashMap 中 hash 冲突的解决方法及原理分析

    我们最先衰老的不是容貌,而是不顾一切的闯劲.有时候,要敢于背上超出自己预料的包袱,真的努力后,你会发现自己要比想象的优秀很多. HashMap冲突的解决方法比较考验一个开发者解决问题的能力. 在Jav ...

  6. 螺丝孔槽中的螺丝拧花了的物理原理分析

    下面是这个emachines 350的背面,一个孔槽里面的螺丝拧花了 俯视螺丝,此时的螺丝是这样的: 这个时候一定是寻找一字的螺丝刀,一字螺丝刀的刀头长度小于上述内径. 为什么是小于而不是大于呢? 因 ...

  7. v割与邮票孔_PCB中邮票孔(半孔)与V-cut原理分析与设计

    前言:在PCB设计过程中,我们经常会遇到 一.邮票孔 如下图所示的即为邮票孔,邮票孔分为拼版作用与连接作用,两者是不同的概念.连接作用的邮票孔一般用在核心板上和模块上,便于与底板和其他电路部分焊接.如 ...

  8. SAP WebClient UI开发工具中attribute文件夹展开的实现原理分析

    For project reason I need to figure out the logic how the field list is assembled when folder " ...

  9. JS中数据类型、内置对象、包装类型对象、typeof关系

    平时在复习JS基础知识时,经常会遇到JS数据类型.基础数据类型.内置对象.包装类型对象,检测数据类型时,用到的typeof值,感觉都差不多,但是又有差异.今天特地整理下,方便理解. JS数据类型 基础 ...

最新文章

  1. 51单片机中将变量、数组、函数设置在固定位置,定位到绝对地址
  2. java der pem_JAVA解析各种编码密钥对(DER、PEM、openssh公钥)
  3. 微课|Python程序设计开发宝典(5.1.2节):修饰器
  4. openvswitch安装、基本操作
  5. C#编程(二十三)----------实现继承
  6. unity visual effect Graph 1
  7. Android 签名
  8. 物理学 物体的运动力学分析之牛顿三定律 单摆的MATLAB运动仿真(一)
  9. 陪集分解的几个简单应用
  10. CocosCreator 基于Assembler实现的图片切割破碎效果及自定义遮罩
  11. Liu C-2021-1: Nontrivial Gates FET
  12. PSD是什么文件格式
  13. 王禹偁:万壑有声含晚籁,数峰无语立斜阳
  14. linux bochs 网络,Linux下Bochs的使用(转载)
  15. 如何把采集到的数据存入mysql_数据采集教程_数据发布_如何发布到数据库MySQL_后羿采集器...
  16. 器械传递的方法_器械传递的原则与方法
  17. DeepMind新AI可生成逼真视频
  18. 区间问题,Huffman树,排序不等式,绝对值不等式,推公式
  19. 人工智能时代,有哪些新的职业机会?
  20. 这辈子会遇见谁,早已命中注定

热门文章

  1. Linux快速上手2:文件名颜色的含义与目录结构
  2. 2019年,这8款自动语音识别方案你应该了解!
  3. 为了王心凌,我拳打电脑管家,脚踢金山毒霸,3分钟用Python撸一个杀毒软件
  4. 众享比特董事长严挺出席2022中国计算机大会“元宇宙、Web3.0、NFT:机遇还是泡沫?”技术论坛
  5. STM32F103驱动ESP8266连接贝壳物联——②串口助手模拟连接贝壳物联
  6. 202009计算机应用基础考前模拟试题,2009年10月自考00018计算机应用基础历年真题及答案...
  7. MPLS技术学习-静态BFD检测静态LSP学习
  8. 你了解个人云盘和企业云盘有什么区别吗?
  9. Xcode项目参数配置——Search Paths
  10. linux程序设计师什么,成为物联网工程师要学些什么?