Kotlin之Lambda表达式和成员引用

Lambda介绍:作为函数参数的代码块

用匿名内部类实现监听器

<!--Java-->
button.setOnClickListener(new OnClickListener(){
       override
       public void onClick(View view){
          <!-- 点击后执行的动作-->
       }
    }
);

现在用Kotlin的Lambda表达式来替换匿名内部类

button.setOnClickListener{<!--点击后执行的动作-->}

Lambda和集合

先看一个例子

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

然后创建一个Person集合,并找出集合中年龄最大的那个

val list = listOf(Person("Alice",29),Person("Bob",31))
println(list.maxBy{it.age})
Person{name=Bob,age=31}

如上使用了Kotlin的库函数,maxBy函数可以在任何集合上调用,且只需要一个实参:一个函数,指定比较哪个值来找到最大值,而花括号中的代码{it.age}就是实现了这个逻辑的lambda

如果lambda刚好是属性的委托,可以用成员引用代替

list.maxBy(Person::age)

Lambda表达式语句

还可以把lambda表达式存储在一个变量中

val sum = { x:Int,y:Int -> x+y }
println(sum(1,2))

还可以直接调用lambda表达式

{println(42)}()

但是这样的语法毫无可读性,也没有什么意义,如果你确实需要把一小段代码封闭在一个代码块中,可以使用库函数run来执行传给它的lambda

run { println(42) }

再回到上面的例子

val list = listOf(Person("Alice",29),Person("Bob",31))
println(list.maxBy{it.age})

如果不用简明的语法重写这个例子,你会得到下面的代码

list.maxBy( { p:Person -> p.age} )

这个代码就一目了然了,花括号里面的代码片段是lambda表达式,把它作为实参传递给函数。这个lambda接受一个Person的参数并返回它的年龄

这个代码还可以简化,如果lambda表达式是函数调用的最后一个实参,它可以放到括号的外面

list.maxBy(){ p:Person -> p.age }

lambda是函数唯一的实参时,还可以去掉调用代码中的空括号

list.maxBy { p:Person -> p.age }

省略lambda参数类型,和局部变量一样,如果lambda参数的类型可以被推导出来,你就不需要显示地指定它。这里以maxBy函数为例,其参数的类型始终和集合中元素的类型相同

list.maxBy { p -> p.age }

使用默认参数类型,仅在实参名称没有显示地指定时这个默认的名称才会生成

list.maxBy{ it.age }

注意: it约定能大大缩短你的代码,但你不应该滥用它。尤其在嵌套lambda的情况下,最后显示地声明每个lambda的参数。否则很难搞清楚it引用的到底是哪个值。

此外,lambda表达式还可以包含更多的语句

val sum = { x:Int,y:Int -> 
    println("Computing the sum of $x and $y...")
    x+y
}

println(sum(1,2)

Computing the sum of 1 and 2...
3

在作用域中访问变量

当在函数中声明一个匿名内部类的时候,在匿名内部类中可以引用函数的参数和局部变量。如果函数内部使用lambda,也可以访问这个函数的参数

fun printMessageWithPrefix(messages:Collec    tion<String>,prefix:String){
        messages.forEach {<!--接收lambda作为实参-->
        println("$prefix $it") <!--在lambda中访问prefix参数-->
    }
}

这里Kotlin和Java的区别就是,在Kotlin中不会仅限于访问final变量,在lambda内部也可以修改这些变量

成员引用

如果你想要当做参数传递的代码已经被定义成了函数,那么你可以将这个函数转换成值,如下使用::运算符来转换

val getAge = Person::age

这种表达式被称为成员引用,它提供简明语法,来创建一个调用单个方法或这访问单个属性的函数值。双冒号把类名称和你要引用的成员名称隔开

如下这个lambda表达式

val getAge = { person:Person -> person.age }

成员引用和调用函数的lambda具有一样的类型,所以可以相互转换

list.maxBy(Person::age)

还可以引用顶层函数,这种情况省略了类名称,直接以::开头。成员引用::salute被当作实参传递给库函数run

fun salute() = println("Salute!")
run (::salute)
Salute!

如果lambda要委托给一个接收多个参数的函数,提供成员引用代替它将会非常方便

val action = {person:Person,message:String -> sendEmail(person,message)}

val nextAction = ::sendEmail
调用
nextAction(...,...)

可以用构造方法引用存储或者延期执行创建类实例的动作,构造方法的引用方式是在双冒号后指定类名称

val createPerson = ::Person <!--创建`Person`实例的动作被保存成了值-->
val person = createPerson("kdp",25)
println(person)

还可以使用同样的方式引用扩展函数

fun Person.isAdult() = age >= 21
val predicate = Person::isAdult

绑定引用

Kotlin1.1允许你使用成员引用语法捕捉特定实例对象上的方法引用

val p = Person("Dmitry",34)
val dmitrysAgeFunction = p::age
println(dmitrysAgeFunction())

注意:dmitrysAgeFunction是一个零函数的参数,在Kotlin1.1之前,你需要显示地写出lambda{p.age},而不是使用绑定成员引用p::age

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