Lambda是什么

在讲高阶函数之前,必须要明白什么是Lambda,简单来讲,Lambda是一种函数的表示方式(言外之意也就是说一个Lambda表达式等于一个函数)。更确切的说:Lambda是一个未声明的函数,会以表达式的形式传递
为什么要用Lambda
设想一下,在Android中实现一个View的点击事件,可以使用如下实现:

View view = findViewById(R.id.textView);
view.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {viewClicked(view);}
});

而如果在Kotlin中使用Lambda,则实现可以简单如下:

val view = findViewById(R.id.image)
view.setOnClickListener { v -> viewClicked(v) }

可以很明显的看出Lambda一方面可以简省很多代码,最重要的一点是Lambda表达式可以避免在抽象类或接口中编写明确的函数声明,进而也避免了类的实现部分(省去了OnClickListener接口这一环节)

Lambda表达式语法

1. lambda 表达式总是被大括号括着;
2. 其参数(如果有的话)在 -> 之前声明(参数类型可以省略);
3. 函数体(如果存在的话)在 -> 后面

具体的写法可以有以下两种写法:

// 第一种
val sum1 = {x: Int, j: Int -> x + j}
// 第二种
val sum2: (x: Int, j: Int) -> Int = {a, b -> a + b }

分析一下上述两种表达式:
第一种比较好理解,首先 ‘=’ 左边声明了一个变量sum1,’=’ 右边是一个Labmda表达式,然后将其赋值给sum1
第二种稍微复杂一点,主要是复杂在左边的sum2: 后面的这一坨代表什么意思。 首先熟悉Kotlin语言的童鞋应该都知道Kotlin函数参数是使用 Pascal 表示法定义(name: type), 因此sum2: 后面的这一坨代表的是一种类型type,那具体代表的是什么类型呢? 在Kotlin中一切皆对象,包括函数也是对象,既然是对象, 同Integer, String等对象一样,一个函数也有自己的类型type
(x: Int, j: Int) -> Int这种表述方式就是表达函数的类型,它表示的是一个需要传入两个Int类型参数,并返回Int类型的函数。 那么如果想表达一个无参并返回String类型的函数该如何表达呢? 答案见1楼

Lambda传递使用

在我们需要使用这两个Lambda表达式的时候可以直接将sum1、sum2传递给一个高阶函数(稍后讲解),或者也可以直接将=之后的表达式传递给高阶函数, 具体如下所示:

val view = findViewById(R.id.image)
view.setOnClickListener { v -> imageClicked(v) }

接下来我们来看一下,上述的 view.setOnClickListener { v -> imageClicked(v) }是如何一步一步演化而来。在这之前我们需要先了解一下什么是高阶函数
高阶函数是什么
以函数作为参数或返回函数的函数被称为高阶函数

定义一个高阶函数

知道了什么是高阶函数之后,我们可以使用一段伪代码来演示如何定义一个高阶函数,如下所示:

fun 高阶函数名(参数函数名:参数函数类型):高阶函数返回类型{高阶函数体...
}

注意:我们姑且将传入当做参数的函数起名为参数函数
写一个具体的实现如下:

fun highOrderFunc(arg1: Int, arg2: Int, paramFunc: (a: Int, b: Int) -> Boolean): Int {return if (paramFunc(arg1, arg2)) {arg1} else {arg2}
}

上面具体实例中,我们定义了一个名为highOrderFunc的高阶函数,并且传入了3个参数,前两个参数是Int类型, 最后一个参数是一个函数,并且函数类型是传入两个Int参数并返回Boolean类型值。最后这个高阶函数自己的返回类型是Int值

使用高阶函数

定义好了一个高阶函数之后,我们就可以将一个Lambda传递给这个高阶函数,完整实例如下所示:

fun highOrderFunc(arg1: Int, arg2: Int, paramFunc: (a: Int, b: Int) -> Boolean): Int {return if (paramFunc(arg1, arg2)) {arg1} else {arg2}
}fun main(args: Array<String>) {val sum1 = {x: Int, j: Int -> x + j}val sum2: (x: Int, j: Int) -> Int = {a, b -> a + b }val max = {x: Int, y: Int -> x > y}println(sum1)println(sum2)println(sum(10, 20))val biggerNum = highOrderFunc(60, 80, max)println("biggerNum is $biggerNum")
}

可以看到,除了sum1和sum2之外,重新定义了一个Lambda函数val max = {x: Int, y: Int -> x > y}, 并且将此Lambda传递给了之前定义的高阶函数highOrderFunc。 这样综合起来所表达的意思就是在传入的两个参数中找出较大的那一个。
最终打印结果如下:

Function2<java.lang.Integer, java.lang.Integer, java.lang.Integer>
Function2<java.lang.Integer, java.lang.Integer, java.lang.Integer>
30
biggerNum is 80

注意:println(sum1)和println(sum2)打印出来的结果都是Function2, 这是Kotlin的一个对象,代表的是一个函数类型

分析

在理解了高阶函数的定义以及使用之后,我们回过头来理解一下 view.setOnClickListener { v -> imageClicked(v) }这个表达式是如何一步一步演化而来。
首先我们可以写一个完整的Lambda,如下所示:

val imageClick: (v: View) -> Unit = {v -> viewClicked(v) }

声明一个函数变量imageClick,并指向一个Lambda函数{v -> viewClicked(v) }。 在Lambda函数体中,调用了viewClicked(v: View?)方法。然后就可以调用此方法,完整代码如下:

class Main2Activity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main2)// 声明函数变量val imageClick: (v: View) -> Unit = {v -> viewClicked(v) }// 声明并初始化View对象val view = View(this)// 调用View的setOnClickListener方法,设置点击监听器,并将imageClick传进去,// 最终点击ImageView时,会调用viewClicked方法view.setOnClickListener(imageClick)}private fun viewClicked(view: View?) {}
}

Lambda表达式也可以传递给一个高阶函数当做参数,因此上述代码中

view.setOnClickListener(imageClick),
=>
view.setOnClickListener({v -> viewClicked(v) })

在 Kotlin 中有一个约定,如果函数的最后一个参数是一个函数,并且你传递一个 lambda 表达式作为相应的参数,你可以在圆括号之外指定它
因此可以实现如下

view.setOnClickListener({v -> viewClicked(v) })
=>
view.setOnClickListener() {v -> viewClicked(v) }

在 Kotlin中还有另外一个约定,如果一个函数的参数只有一个,并且参数也是一个函数,那么可以省略圆括号

view.setOnClickListener() {v -> viewClicked(v) }
=>
view.setOnClickListener{v -> viewClicked(v) }

总结

Lambda和高阶函数理解起来有点绕,需要大量的练习和实验才能慢慢的理解(一些复杂的代码写的多了 习惯了之后自然而然的就没有为什么要这样写了 哈哈)
文章一开始我们说了使用Lambda可以省去接口定义和实现这一环节,但是是有条件的,此接口必须只有一个抽象方法需要实现,才可以使用Lambda替代(比如OnClickListener、OnItemClickListener)。如果多于1个抽象方法,则不能使用Lambda进行替代(比如OnItemSelectedListener)。
具体看如下代码:

val listView = findViewById(R.id.listView) as ListViewlistView.onItemClickListener = AdapterView.OnItemClickListener { adapterView, view, i, l -> }listView.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {override fun onItemSelected(adapterView: AdapterView<*>, view: View, i: Int, l: Long) {}override fun onNothingSelected(adapterView: AdapterView<*>) {}}

学习交流

欢迎入群交流学习,Android、Java开发技术交流群

  • QQ群:810970432
  • email:geduo_83@163.com

Kotlin-简约之美-进阶篇(十一):高阶函数相关推荐

  1. kotlin修炼指南8—集合中的高阶函数

    点击上方蓝字关注我,知识会给你力量 Kotlin对集合操作类新增了很多快捷的高阶函数操作,各种操作符让很多开发者傻傻分不清,特别是看一些Kotlin的源码或者是协程的源码,各种眼花缭乱的操作符,让代码 ...

  2. JavaScript 面向对象编程(三) —— 函数进阶 / 严格模式 / 高阶函数 / 闭包 / 浅拷贝和深拷贝

    本篇为 JavaScript 进阶 ES6 系列笔记第三篇,将陆续更新后续内容.参考:JavaScript 进阶面向对象 ES6 :ECMAScript 6 入门 系列笔记: JavaScript 面 ...

  3. Kotlin学习路(七):高阶函数与内联函数关系

    <本文学习郭神<第三行代码>总结> 定义用法 高阶函数:如果一个函数接收另一个函数作为参数,或者返回值的类型是另一个函数,那么该函数称为高阶函数. 语法规则:(String, ...

  4. python中sort返回值_Python函数你真的都学会了吗?来看看这篇Python高阶函数!

    二.高阶函数 高级函数, 英文叫 Higher-order Function. 那么什么是高阶函数呢? 在说明什么是=高阶函数之前, 我们需要对函数再做进一步的理解! 2.1 函数的本质 函数的本质是 ...

  5. Python函数你真的都学会了吗?来看看这篇Python高阶函数!

    二.高阶函数 高级函数, 英文叫 Higher-order Function. 那么什么是高阶函数呢? 在说明什么是=高阶函数之前, 我们需要对函数再做进一步的理解! 2.1 函数的本质 函数的本质是 ...

  6. Kotlin 编程核心基石—高阶函数

    前言 1. 高阶函数有多重要? 高阶函数,在 Kotlin 里有着举足轻重的地位.它是 Kotlin 函数式编程的基石,它是各种框架的关键元素,比如:协程,Jetpack Compose,Gradle ...

  7. Kotlin——高阶函数详解与标准的高阶函数使用

    一.高阶函数介绍 在介绍高阶函数之前,或许您先应该了解Kotlin中,基础函数的使用与定义.您可以参见Kotlin--初级篇(七):函数(方法)基础使用这边文章的用法. 在Kotlin中,高阶函数即指 ...

  8. python order函数_Python进阶内容(一)--- 高阶函数 High order function

    0. 问题 # 本文将围绕这段代码进行Python中高阶函数相关内容的讲解 # 文中所有代码的兼容性要求为:Python 3.6,IPython 6.1.0 def addspam(fn): def ...

  9. Kotlin中的高阶函数

    博客地址sguotao.top/Kotlin-2018- 在Kotlin中,高阶函数是指将一个函数作为另一个函数的参数或者返回值.如果用f(x).g(x)用来表示两个函数,那么高阶函数可以表示为f(g ...

  10. Kotlin 使用高阶函数实现回调

    lambda 和 高阶函数 之前学习了 lambda 和高阶函数,然后在 android 开发中对 onClick 事件进行监听是一个很常用的功能,kotlin 的常规实现如下: rootView.s ...

最新文章

  1. tableview插入刷新_iOS中tableview的几种刷新
  2. Orecle基本概述(2)
  3. 简单几步教你怎么在路由器上搭建PHP环境的网站
  4. php补充 扩展,php补充安装扩展支持
  5. 温故而知新:HttpApplication,HttpModule,HttpContext及Asp.Net页生命周期
  6. Es6常用方法filter
  7. iOS7初体验(2)——单元测试
  8. 前端如何做极致的首屏渲染速度优化
  9. 阻塞非阻塞,同步异步四种I/O方式
  10. 【Linux使用】Centos 7 YUM仓库配置文件代理服务器设置
  11. comment on 视图_oracle 使用comment语句添加表注释
  12. 清华计算机科学与技术专业收分,2016年清华大学计算机科学与技术专业最低分是多少?...
  13. MangoDB的基本操作
  14. js身份证号计算性别
  15. iOS adhoc ipa 安装
  16. 头条 上传图片大小_无锡抖音巨量运营培训南天值得选择——鹰手营子矿头条...
  17. GIS数据网站分享(长期更新)
  18. 为什么感觉现在电脑病毒少了?
  19. android极光富媒体推送,极光推送如何在android客户端接收富媒体
  20. Java内存模型(JMM)学习总结

热门文章

  1. 在android apk中调用@hide方法
  2. 第四篇 彩云之南(2017.1.31-2017.2.8)
  3. [C++] namespace 名字空间
  4. 爬虫学习(13):爬取坑爹网gif图
  5. i5 13420H和i7 13700h差距 i513420H和i713700h对比
  6. NLP第二课(搜索)
  7. 计算机专业考研三件套,套装4册 天勤计算机考研2022版
  8. An instance-based learning approach for thresholding in crop images under different outdoor conditio
  9. 三维电子沙盘 三维数字虚拟沙盘 开发教程第39课 交互触摸查询面板的调用
  10. socket指南(1)