Kotlin 学习笔记: lambda编程

Kotlin学习笔记:概述
Kotlin学习笔记:基本语法和函数
Kotlin学习笔记:类和接口
Kotlin学习笔记:lambda编程
Kotlin学习笔记:类型系统
Kotlin学习笔记:泛型
Kotlin学习笔记:注解和反射

什么是lambda表达式

“Lambda 表达式”(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数。
lambda表达式本质上是可以传递给其他函数的一段代码。lambda可以作为函数的参数和返回值。大大简化了代码。

lambda表达式的语法为

image.png

集合的函数式API

  • filter

filter 可以移除集合中不满足条件的元素。

>>> val list = listOf(1, 2, 3, 4)
>>> list.filter { it % 2 == 0 }
[2, 4]
image.png
  • map

map函数对集合中的每个元素应用给定的函数并把结果收集到一个集合中。

>>> val list = listOf(1, 2, 3, 4)
>>> list.map { it * it }
[1, 4, 9, 16]
image.png
  • all,any,find,count

这些主要用于对集合的判定

假如我们需要判定一群人中的年龄是否小于28岁

val canBeInClub27 = { p: Person -> p.age <= 27 }

使用all判定是否所有人都小于28岁

>>> val people = listOf(Person("Alice", 27), Person("Bob", 31))
>>> println(people.all(canBeInClub27))
false

使用any判定其中的一些人小于28岁

>>> println(people.any(canBeInClub27))
true

使用count计算小于28岁的人的个数

>>> val people = listOf(Person("Alice", 27), Person("Bob", 31))
>>> println(people.count(canBeInClub27))
1

使用find找到所有小于28岁的人信息

>>> val people = listOf(Person("Alice", 27), Person("Bob", 31))
>>> println(people.find(canBeInClub27))
Person(name=Alice, age=27)
  • groupBy

groupBy可以用于将列表转换成分组的map

>>> val people = listOf(Person("Alice", 31),
... Person("Bob", 29), Person("Carol", 31))
>>> println(people.groupBy { it.age })
image.png
  • flatmap和flatten

flatMap函数做两件事情:首先根据作为实参给定的函数对集合中的每个元素做变换(maps),然后把多个列表合并(flatten)成一个列表。

>>> val strings = listOf("abc", "def")
>>> println(strings.flatMap { it.toList() })
[a, b, c, d, e, f]
image.png

flatten可以将多个集合的元素合并到一个集合中。

>>>  val langs = listOf(listOf("js"), listOf("Java", "Kotlin"), listOf("C++", "PHP", "Python"))
>>> println(langs.flatten())
[js, Java, Kotlin, C++, PHP, Python]

序列

前面讲述了很多链式集合调用的例子,但是这些函数会及早的创建中间集合,也就是说每一步的中间结果都存储在一个临时列表里。所以,当直接使用链式集合的函数处理集合元素数量特别多的情况下,性能比较低。而序列可以避免创建临时中间变量。

举例来讲

有一个Person类,它有名字和年龄两个属性。

data class Person(val name: String, val age:Int)

要找出名字前缀是“J”的人的姓名

用链式集合函数

persons.map { person -> person.name }
            .filter { it.startsWith("J") }
            .toList()

编译代码,再将其反编译

    //....
    Object element$iv$iv;
      while(var4.hasNext()) {
         element$iv$iv = var4.next();
         Person person = (Person)element$iv$iv;
         String var11 = person.getName();
         destination$iv$iv.add(var11);
      }
    //...   

用序列实现

 persons.asSequence()
            .map { person -> person.name }
            .filter { it.startsWith("J") }
            .toList()

反编译后代码

List persons = CollectionsKt.listOf(new Person[]{new Person("Jack", 25), new Person("Cat", 29)}); 
SequencesKt.toList(SequencesKt.filter(SequencesKt.map(CollectionsKt.asSequence((Iterable)persons), (Function1)null.INSTANCE), (Function1)null.INSTANCE));

使用Java函数式接口

首先说函数式接口的定义:只有一个抽象方法的接口称为函数式接口,也就是SAM(单抽象方法)。

在Android中,最常用的接口就是OnClickListener了。现在我们以监听一个button的点击事件为例,来说明kotlin是如何使用Java函数式接口的。

用java编写监听button点击事件

    btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {...}
        });

用kotlin编写button点击事件

btn.setOnClickListener{...}

我们还记得在函数文章中,我们用过匿名表达式。

  val vto = layout.viewTreeObserver
        vto.addOnGlobalLayoutListener(object: ViewTreeObserver.OnGlobalLayoutListener       {
            @RequiresApi(Build.VERSION_CODES.JELLY_BEAN)
            override fun onGlobalLayout(){
                layout.viewTreeObserver.removeOnGlobalLayoutListener(this)
                val height = layout.measuredHeight
                val width = layout.measuredWidth
            }
        })

OnGlobalLayoutListener接口也只有一个方法,符合函数式接口的定义。那么,这个方法可以用lambda简化吗?答案是不可以。因为包含layout.viewTreeObserver.removeOnGlobalLayoutListener(this)语句。

在lambda 内部没有匿名对象那样的this。这意味着没有办法引用到lambda转换成的匿名类实例。

带接收者的lambda:with和apply

很多语言都有这样的语句:可以用他们对同一个对象执行多次操作,而不需要把对象的名称写出来。

with 和apply就是这样的语句。

  • with

还是以一个例子开始:创建一个函数打印字母表。

一般情况下,都这样写

fun alphabet(): String {
    val result = StringBuilder()
    for (letter in 'A'..'Z') {
        result.append(letter)
    }
    result.append("\nNow I know the alphabet!")
    return result.toString()
} 
>>> println(alphabet())
ABCDEFGHIJKLMNOPQRSTUVWXYZ
Now I know the alphabet!

而用with,可以这样写

fun alphabet(): String {
    val result = StringBuilder()
    return with(result)
        { for (letter in 'A'..'Z')
            {this.append(letter)}
            append("\nNow I know the alphabet!")
            this.toString()
        }
    }
  • apply

apply几乎和with一模一样,唯一的区别是apply始终会返回作为实参传递给他的对象。

fun alphabet() = StringBuilder().apply{ 
    for (letter in 'A'..'Z') {
        append(letter)
    }
    append("\nNow I know the alphabet!")
}.toString()

高阶函数

高阶函数:以另一个函数作为参数或者返回值的函数。

  • 函数类型

为了声明一个以lambda作为实参的函数,需要知道如何声明对应的形参类型。

语法:将函数参数类型放在括号中,紧接着是一个箭头和函数的返回类型

  • 调用作为参数的函数类型
fun searchRepos(
        service: ZhihuService,
        query:String,
        onSuccess:(repos: List<Repo>) -> Unit,
        onError: (error: String) -> Unit) {
   //...
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271

推荐阅读更多精彩内容

  • 写在开头:本人打算开始写一个Kotlin系列的教程,一是使自己记忆和理解的更加深刻,二是可以分享给同样想学习Kot...
    胡奚冰阅读 1,170评论 0 6
  • lambda即lambda表达式,简称lambda。本质上是可以传递给其它函数的一小段代码。有了lambda,可以...
    程自舟阅读 16,036评论 1 26
  • 定义 Lambda表达式,本质上就是可以传递其他函数的一小段代码。有了lambda,可以轻松的把通用的代码结构抽取...
    m1Ku阅读 504评论 0 0
  • 原文链接:https://github.com/EasyKotlin 值就是函数,函数就是值。所有函数都消费函数,...
    JackChen1024阅读 5,840评论 1 17
  • 教师的假期,不光是休整身体,更是一个充电的好机会。我们要有终身学习的精神。从7月29日-8月4日,我将参加长洲区校...
    欧洁兰阅读 365评论 0 0