1. 程式人生 > >Kotlin基礎(四)Lambda編程

Kotlin基礎(四)Lambda編程

構造 引用 元素 允許 其他 create text 顯示 tag

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函數的唯一區別是會返回作為實參傳遞給它的對象(接收者對象)

Kotlin基礎(四)Lambda編程