Kotlin基础 - 第七章lambda表达式

本文深入探讨了Kotlin中的lambda表达式,包括它们的语法、在作用域访问变量的能力、与Java函数式接口的互操作以及带接收者的lambda如with和apply的使用。通过实例展示了如何简化代码,例如在集合操作中使用filter和map,以及如何使用groupBy和flatMap处理数据。文章强调了lambda表达式在避免代码重复和提高代码可读性方面的优势。
摘要由CSDN通过智能技术生成

kotlin中的lambda表达式



#### [kotlin官方文档 https://www.kotlincn.net/docs/reference/](https://www.kotlincn.net/docs/reference/) ####

lambda即lambda表达式,简称lambda。本质上是可以传递给其它函数的一小段代码。有了lambda,可以轻松地把通用代码结构抽取成库函数。lambda最常见的用途是和集合一起配合。kotlin甚至还拥有带接收者的lambda,这是一种特殊的lambda。

lambda的表达式和成员引用

lambda简介:作为函数参数的代码块

代码中存储和传递一小段行为是常有的任务。在老版本Java中很多需要匿名内部类来实现(java8也引入了lambda,大为改观),语法太过啰嗦。
函数式编程提供了另外一种解决方案:把函数当作值来对待。可以直接传递函数,而不需要先声明一个类再传递这个类的实例。使用lamdba表达式不仅会使代码更简洁,并且可以高效地直接传递代码快作为函数参数。

笔者注,后文我会省略大段的lambda理论文字的介绍,因为在我的认知中,接触了java8(尤其是Android)的一定对lambda有一定的认知,如果没有请自行查阅资料。

	//点击监听 java lambda
   	btn.setOnClickListener(view ->...);

  	//点击监听 kotlin lambda
    btn.setOnClickListener { ... }

kotlin的lambda相对于java8的lambda语法更简洁,事实上它们做的事情是一样的,都是替代了匿名内部类对象。

良好的编程风格主要原则之一就是避免代码中的任何重复。kotlin的lambda可以帮助避免代码重复(因为对集合执行通常遵循通用模式)。

	//建立数据类Person作为数据源
	data class Person(val name: String, val age: Int) {
	     
	}

假设需求为找到列表年龄最大的人,平时我们打代码可能是这样的。

	data class Person(val name: String, val age: Int) {
	
	}
	//未使用lambda表达式
	fun findTheOldest(people:List<Person>){
	    var maxAge=0  //存储最大年龄
	    var theOldest:Person?=null //存储年龄最大的人
	    for (person in people){
	        if (person.age>maxAge){ //循环赋值比现在年龄大的改变最大值
	            maxAge=person.age
	            theOldest=person
	        }
	    }
	    println(theOldest)
	}
	
	 //数据源
    val people = listOf(Person("jack", 29),
            Person("nick", 23),
            Person("jone", 26))

    findTheOldest(people)//Person(name=jack, age=29)

如果我们使用lambda表达式,我对门的代码直接可以简化成下面的样子

	class Person(var name: String, var age: Int) {
	
	}


 
    val people = listOf(
        Person("小明", 12),
        Person("小红", 12),
        Person("小花", 12),
        Person("小美", 12),
        Person("小帅", 12)
    )

   println(people.maxBy { it.age % 2 }!!.name)  //小帅

maxby函数可以在任何集合上调用,且只需要一个实参:一个函数,指定比较哪个值来找到最大元素。{it.age}就是实现了这个逻辑的lambda。它接收一个集合中元素作为实参(it引用)并且返回用来比较的值。如上述代码中,集合元素是Person对象,用来比较的是存储在其age属性中的年龄。
如果lambda刚好是函数或者属性委托,可以用成员引用替换。

	val people = listOf(
        Person("小明", 12),
        Person("小红", 14),
        Person("小花", 20),
        Person("小美", 10),
        Person("小帅", 13)
    )
	
	//注意两者的区别这种传递属性值的方式应当使用在括号里面
    println(people.maxBy(Person::age)!!.name)  //小花

主使用成员引用的方式传递闭包(代码块)的时候仅可以传递属性值

lambda表达式语法

如前所述(更多详情自行查阅资料或参 见初识lambda) lambda把一小段行为进行编码,既能当作值传递又能独立声明到一个变量中存储。

  	var sum = { x: Int, y: Int -> x + y }
    println(sum(1, 6)) //7

也可以无意义的直接调用lambda表达式

	//直接调用无意义(等同于直接执行lambda具体代码)
  	{ println(42)}()//42

正确姿势应该使用kotlin库函数run。

  	//正确姿势un调用
    run { println(42) }//42

回到people的例子,不用任何简明语法来重写。

    //未简化的标注lambda
    people.maxBy({ P:Person ->P.age} )

kotlin有一种语法约定,如果lambda表达式是函数调用的最后一个实参,它可以放到括号外面。

  	//lambda是函数调用的最后一个实参,可以放到()外
    people.maxBy( ){ P:Person ->P.age}

当lambda是函数唯一实参时,还可以去掉()

 	//lambda是函数唯一实参,可以省略()
    people.maxBy{ P:Person ->P.age}

三种语法语义完全一样,但是最后一种更易读。但是当lamdba有两个或多个实参时,不能把超过一个的lambda放到外面,推荐使用常规语法。

把当然,lambda也能作为命名实参传递

	val people = listOf(
        Person("小明", 12),
        Person("小红", 14),
        Person("小花", 20),
        Person("小美", 10),
        Person("小帅", 13)
    )


  var str = people.joinToString(separator = " ", transform = { people: Person -> people.name })
  println(str)  // 小明 小红 小花 小美 小帅

因为只有一个实参,所以可以放在括号外

	var str = people.joinToString(separator = " ") { people: Person -> people.name }

    println(str)	// 小明 小红 小花 小美 小帅

甚至可以根据类型推导特性而移除参数类型。

 	//显示的写出参数推导类型
    var str = people.joinToString(separator = " ") { people: Person -> people.name }

    //推导出参数类型
	var str = people.joinToString(separator = " ") { people -> people.name }

    println(str)

类型推导与局部变量一样,如果能成功被推导,就不需要显示的指定。

使用默认参数名称(注意)

 	//使用默认参数名称
    people.maxBy { it.age} //"it"是自动生成的参数名称

默认名称it只会在实参名称没有显示的指定时候才会生成。it能大大缩短简化代码,但是不应该滥用,尤其是在lambda嵌套情况下,最好显示声明lambda参数。否则很难搞清it引用的到底是哪个值,本末倒置。

如果用变量存储lambda,就没有可以推断出参数类型的上下文,必须显示的指定参数。

	//变量存储lambda,必须显示指定参数类型
 	var getAge = {person:Person -> person.age}

	//输出结果:Person(name=小花, age=20)
    println(people.maxBy(getAge)) 

lambda当然也能包含更多语句。

    val sum = { x: Int, y: Int ->
        println("this is $x and $y and sum is")
        x+y
    }
    //this is 1 and 2 and sum is
    // 3
    println(sum(1,2))

在作用域访问变量

lambda表达式有个形影不离的概念:从上下文中捕捉变量。

当在函数内部声明一个匿名内部类的时候,能够在这个匿名内部引用这个函数的参数和局部变量。lambda同样可以。

	//使用lambda进行循环的函数
	fun p
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值