Kotlin基础(四)Lambda编程

Lambda编程

一、Lambda表达式和成员引用

一)Lambda表达式语法

1  //注意与Java8中的区别
2     val sum={ x:Int,y:Int -> x+y }
3     println(sum(5,6))
4     run { print(33) }
 1 data class Person(val name:String,val age:Int)
 2
 3 fun main(args: Array<String>) {
 4     val persons= listOf<Person>(Person("Tom",3),Person("Jerry",2))
 5     //println(persons.maxBy { it.age })
 6
 7     //不使用任何简明语法的重写
 8     //println(persons.maxBy({p:Person -> p.age}))
 9
10     //如果lambda表达式是函数调用的最后一个实参,可以把它放到括号外面,但只能放一个
11     //println(persons.maxBy() { p:Person -> p.age })
12
13     //lambda为唯一实参时,可以省略小括号
14     //println(persons.maxBy { p:Person -> p.age })
15
16     //如果lambda的参数类型可以被推断出来,可以省略它
17     //println(persons.maxBy { p -> p.age })
18     //使用原则:可以先不声明参数类型,观察编译器是否报错
19
20     //最简形式:使用默认参数名it代替参数名。如果当前上下文期望的
21     //是只有一个参数的的lambda且这个参数的类型可以推断出来。
22     println(persons.maxBy { it.age })
23 }
 1 fun main(args: Array<String>) {
 2     //与Java不同,Kotlin允许在lambda内部访问非final变量,甚至修改它们
 3     //默认情况下,局部变量的声明周期被限制在声明这个变量的函数中。但是如果
 4     //它被lambda捕捉了,使用这个变量的代码可以被存储并稍后再执行。
 5
 6     fun tryToCountButtonClicks(button:Button):Int{
 7         var count=0
 8         button.onClick {count++}
 9         //这里会始终返回0
10         return count
11     }
12 }

成员引用:

//与Java8一样,如果把函数转换为一个值,你就可以传递它
    var getAge=Person :: age

    //还可以引用顶层函数
    run { ::tang }

    //构造方法引用存储或延期执行创建实例类的动作
    val createPerson= ::Person
    val p=createPerson("Price",48)
    println(p)

    //引用扩展函数
    fun Person.isAdult()= age>=21
    val isAdult=Person::isAdult

二)集合的函数式API

1.filter函数:遍历集合并选出应用给定lambda后返回true的那些元素。

1 val list=listOf(1,2,3,4,5,6)
2 println(list.filter{it%2==0})
3 /*[2, 4, 6]*/

2.map函数:对集合中的每一个运用给定函数并把结果收集到一个新集合。

val list= listOf(1,2,3)println(list.map{it*it})

3.all函数:判断是否所有函数满足判定式

1 val list= listOf(1,2,3,4,5,6,7)
2 println(list.all{it>3})//false

4.any函数:检查是否至少存在一个匹配的元素

1 val list= listOf(1,2,3,4,5,6,7)
2 println(list.any { it>3 })//true

5.find函数:找到第一满足判定式的元素

1 val list= listOf(1,2,3,4,5,6,7)
2 println(list.find { it>3 })//4

6.groupBy函数:把列表转换为分组的map

1     val persons= listOf<Person>(Person("Tom",22), Person("Jimmy",22)
2     , Person("Jack",33),Person("Blank",33), Person("Price",50))
3     println(persons.groupBy { it.age })
4     /*{22=[Person(name=Tom, age=22), Person(name=Jimmy, age=22)],
5     33=[Person(name=Jack, age=33), Person(name=Blank, age=33)],
6     50=[Person(name=Price, age=50)]}*/

7.flatMap函数:处理嵌套集合中的元素

1 val list= listOf<String>("abc","de","fchi")
2 println(list)//[abc, de, fchi]
3 println(list.flatMap { it.toList() })
4  /*[a, b, c, d, e, f, c, h, i]*/

8.flatten函数:只是平铺不做任何变换

9.惰性操作集合:序列

 1 fun main(args: Array<String>) {
 2     val persons= listOf<Person>(Person("Ajax",2), Person("Bob",6),
 3             Person("Tom",5), Person("Auth",3))
 4     persons.map(Person::name).filter { it.startsWith("A") }
 5     persons.map { p:Person ->p.name }.filter { it.startsWith("A") }
 6     /*
 7     * 上面的代码存在的问题:链式调用会创建两个列表,导致效率低下
 8     * 此时可以使用序列
 9     * */
10
11     persons.asSequence()         //把初始集合转换成序列
12             .map(Person::name)   //序列支持和集合相同的API
13             .filter { it.startsWith("A") }
14             .toList()            //转换回集合
15
16     /*
17     * 序列操作分为两类:中间和末端。中间操作返回的是另一个序列,
18     * 末端操作返回的是一个结果,这个结果可能是集合、元素、数字,
19     * 或者其他从初始集合变换序列中获取的任意对象。
20     * */
21     //中间操作始终是惰性的
22     listOf(1,2,3,4).asSequence()
23             .map { println("map($it)"); it*it }    //没有末端操作不会被执行
24             .filter { println("filter($it)") ; it%2==0}  //没有末端操作不会被执行
25 }

注意:序列与Java8的Steam的区别:序列不支持在多个CPU上并行执行。

三)使用Java函数式接口

1 /*Java*/
2 void post(int delay,Runnable com){}
TestIt().post(1000){ //注意整个程序只会创建一个Runnable实例
     println("Run it")
}
1 fun handle(id : String){      //lambda会捕捉id这个变量
2     TestIt().post(1000){ println("Run it $id")} //所以每次调用都会创建新的实例
3 }

SAM构造方法:显示地lambda转换为函数式接口

1 fun createAllDoneRunnable() :Runnable{
2     //SAM构造方法名称和函数式接口名称一样,且只接收一个参数
3     return Runnable { println("All done") }
4 }
5
6 //SAM构造方法还可以把从lambda生成的函数接口实例,存储在变量中
7 val runIt= Runnable { println("Rock & Roll") }

四)带接收者的lambda:with与apply

1.with函数

 1 fun alphabet() :String{
 2     val result=StringBuilder()
 3     for (letter in ‘A‘..‘Z‘){
 4         result.append(letter)
 5     }
 6     result.append("\nDone")
 7     return result.toString()
 8 }
 9
10 //用with函数简化
11 fun alphabe2() : String{
12     val result=StringBuilder()
13     //with结构实际上是一个接收两个参数的函数,一个参数
14     //是result另一个是lambda表达式
15     return with(result){
16         for (letter in ‘A‘..‘Z‘){
17             this.append(letter)
18         }
19         //可省略this
20         append("\n Done2")
21         toString()
22     }
23 }
24
25 //进一步简化
26 fun alphabet3()= with(StringBuilder()){
27     for (letter in ‘A‘..‘Z‘){
28         append(letter)
29     }
30     append("\n Done3")
31     toString()
32 }

2.apply函数

几乎与with函数一样,与with函数的唯一区别是会返回作为实参传递给它的对象(接收者对象)

时间: 2024-08-29 20:22:37

Kotlin基础(四)Lambda编程的相关文章

Python全栈开发【基础四】

Python全栈开发[基础四] 本节内容: 匿名函数(lambda) 函数式编程(map,filter,reduce) 文件处理 匿名函数 lambda表达式:对于简单的函数,存在一种简便的表示方式,即lambda表达式 1 #这段代码 2 def calc(n): 3 return n**n 4 print(calc(10)) 5 6 #换成匿名函数 7 calc = lambda n:n**n 8 print(calc(10)) 匿名函数主要是和其它函数搭配使用 举例: 1 ########

python基础之socket编程

python基础之socket编程   一 TCP/IP五层模型 在每一层都工作着不同的设备,比如我们常用的交换机就工作在数据链路层的,一般的路由器是工作在网络层的. 在每一层实现的协议也各不同,即每一层的服务也不同.下图列出了每层主要的协议. 各层功能 注明:ARP和RAPR两个到底属于哪一层呢? 由于IP协议使用了ARP协议,所以经常把ARP协议划到网络层,但是ARP协议是为了从网络层使用的IP地址解析出在数据链路层使用的MAC地址,所以有些地方也把ARP协议划分到数据链路层,但是一般情况下

五本书籍助你从零基础学习java编程到精通之路

前天的文章给大家介绍了Java初学者应该学习哪些基础,亦是美网络小编从Java的三个大方向:J2SE.J2EE.J2ME对大家做了前景分析,这两天也收到了大家的很多反馈,很多小伙伴看了后对自己的Java编程方向有了比较明确的目标,也有小伙伴们说,要是能提供一些Java初学者应看的书籍就更好了,其实推荐Java书籍已经被规划在小编写的Java编程系列文章之中,常言道:书中自有黄金屋,书中自有颜如玉,下面亦是美网络小编给大家推荐的Java书籍中虽然没有黄金屋和颜如玉,但却能让Java编程的初学者快速

Java基础之网络编程

Java网络编程 课前思考1. 什么是TCP/IP协议?2. TCP/IP有哪两种传输协议,各有什么特点?3. 什么是URL?4. URL和IP地址有什么样的关系?5. 什么叫套接字(Socket)?6. 套接字(Socket)和TCP/IP协议的关系?7. URL和套接字(Socket)的关系?8.1 网络编程基本概念,TCP/IP协议简介 8.1.1 网络基础知识      网络编程的目的就是指直接或间接地通过网络协议与其他计算机进行通讯.网络编程中有两个主要的问题,一个是如何准确的定位网络

Python 基础之socket编程(二)

Python 基础之socket编程(二) 昨天只是对socket编程做了简单的介绍,只是把socket通信的框架搭建起来,要对其中的功能进行进一步的扩充,就来看看今天的料哈! 一.基于tcp的套接字 1. tcp的服务端 ss = socket() #创建服务器套接字 ss.bind() #把地址绑定到套接字 ss.listen() #监听链接 inf_loop: #服务器无限循环 cs = ss.accept() #接受客户端链接 comm_loop: #通讯循环 cs.recv()/cs.

零基础如何学习编程

零基础如何学习编程 心得笔记 自学编程2年来,加过n多群,泡过n多论坛,接触过心怀激情的编程新人,遇到过沉着冷静的技术大牛--编程,吸引了一批又一批的热血青年,或许是为了理想,或许是心中的爱好,不断有新人的加入,也不断有人从编程中退出.编程的入场入口只有一个,出场的出口却很多.自学编程的新人,有很大一部分卡在了入门上,对此,我想写下对编程入门的一些拙见,权当抛砖引玉,或对或错,还望同学们自己鉴定.1.零基础,打算自学编程,应具备哪些的知识?答:对于入门阶段,对知识水平的要求并不算高,或者说很低,

Object Pascal 语法之语言基础(四)

1.8 过程与函数 过程与函数是实现一定功能的语句块,是程序中的特定功能单元.可以在程序的其他地方被调用,也可以进行递归调用.过程与函数的区别在于过程没有返回值,而函数有返回值. 1.过程与函数的定义过程与函数的定义包括过程原型或函数原型.过程体或函数体的定义.过程定义的形式如下: procedure ProcedureName(ParameterList); directives; var LocalDeclarations; begin statements end; ProcedureNa

Python 基础之socket编程(三)

python 基础之socket编程(三) 前面实现的基于socket通信只能实现什么呢?在tcp协议的通信中就是一个用户说一句,服务端给你回一句,你再给服务端说一句,服务端再给你回一句,就这样一直友好的玩耍下去了.等等,又有一个用户来了,他呢也想和和服务端进行一下交流,于是他就给服务端发送了一条消息,之后等呀等不知过了多久,任然没有等到服务端给他发挥的消息,只有什么时候他就可以和服务端愉快的玩耍了呢?这个就需要第一个用户退出和服务器的链接,此时第二个客户端才会和服务端建立起链接,此时此刻,他才

JAVA SE 8 学习笔记(三)使用lambda编程

三.使用lambda编程 3.1 延迟执行 所有lambda表达式都是延迟执行的,如果希望立即执行一段代码,则没必要使用lambda表达式 延迟执行代码原因可能有: ·在另一个线程中运行代码 ·多次运行代码 ·在某个算法的正确时间点上运行代码 ·在某些情况发生时运行代码(如按钮点击.数据到达) ·只有在需要时运行代码 例如: public static void info(Logger logger, Supplier<String> message) { if (logger.isLogga