1什麼時匿名函數
定義函數時不取名字的函數,我們稱之爲匿名函數,匿名函數通常整體傳遞給其他函數,或者從其他函數返回。
匿名函數對Kotlin來說很重要,有了他,我們能夠根據需要制定特殊規則,輕鬆定製標準庫裏的內置函數
fun main(){
val total:Int = "Mississippi".count()
println(total)//字符串長度
val totalS:Int =
"Mississippi".count({letter->letter =='s'})
println(totalS)//s字符個數
}
2函數類型與隱式返回
匿名函數也有類型,匿名函數可以當做變量賦值給函數類型變量,就像其他變量一樣,匿名函數就可以在代碼裏傳遞了。變量有類型,變量可以等於函數,函數也會有類型。函數的類型,由傳入的參數和返回值類型決定。
和具名函數不一樣,除了極少情況外,匿名函數不需要return關鍵字來返回數據,匿名函數會隱式或自動返回函數體最後一行語句的結果。
fun main(){
//變量的類型是一個匿名函數
val blessingFunction:()->String
blessingFunction = {
val holiday = "National Day."
"Happy $holiday"
}
println(blessingFunction())
}
3匿名函數參數
和具名函數一樣,匿名函數可以不帶參數,也可以帶一個或者多個任何類型的參數,需要帶參數時,參數的類型放在匿名函數的類型定義中,參數名則放在函數定義中
fun main(){
val blessingFunction:(String)->String
blessingFunction = {name->
val holiday = "National Day."
"$name,Happy $holiday"
}
println(blessingFunction("Jack"))
}
4 it關鍵字
定義只有一個參數的匿名函數時,可以用it關鍵字表示參數名。當你需要傳入兩個值參,it關鍵字就不能用了。
fun main(){
val blessingFunction:(String)->String
blessingFunction = {
val holiday = "National Day."
"$it,Happy $holiday"
}
println(blessingFunction("Jack"))
}
it非常重要,應用廣泛。函數式編程很多情況下都用
5匿名函數的類型推斷
定義一個變量時,如果已把匿名函數作爲變量賦值給他,就不需要顯示指明變量類型。
fun main(){
val blessingFunction = {
val holiday = "National Day."
"Happy $holiday"
}
println(blessingFunction())
}
和java代碼塊要區分出來。
類型推斷也支持帶參數的匿名函數,但爲了幫助編譯器更準確的推斷變量類型,匿名函數的參數名和參數類型必須有。
fun main(){
val blessingFunction:(String ,Int)->String = {name,year->
val holiday = "National Day."
"$name ,Happy $holiday $year"
}
//或者下面這樣
val blessingFunction = {name:String,year:Int->
val holiday = "National Day."
"$name ,Happy $holiday $year"
}
println(blessingFunction("Jack",2027))
}
6什麼是lambda
我們將匿名函數稱爲lambda,將他的定義稱爲lambda表達式,他的返回數據稱爲lambda結果。爲什麼叫lambda?lambda也可以用希臘字符“入”表示,是lambda演算的簡稱,lambda演算是一套數理演算邏輯,有數學家Alonzo Church於20世紀30年代發明,在定義匿名函數時 ,使用了lambda演算記法。
7定義參數是函數的函數
函數的參數是另一個函數
fun main(){
val getDiscountWords = {goodsName:String,hour :Int ->
val currentYear = 2027
"${currentYear}年,雙11${goodsName}促銷倒計時:$hour 小時"
}
showOnBoard("衛生紙",getDiscountWords)
}
//具名參數
fun showOnBoard(goodsName:String,showDiscount::(String,Int)->String){
val hour = (1..24).shuffled().last()
println(showDiscount(goodsName,hour))
}
8簡略寫法
如果一個函數的lambda參數排在最後,或者是爲一個參數,那麼闊住lambda值參的一對圓括號就可以省略
fun main(){
"Mississippi".count({it == 's'})
"Mississippi".count{it == 's'}
}
fun main(){
showOnBoard("衛生紙"){goodsName:String,hour :Int ->
val currentYear = 2027
"${currentYear}年,雙11${goodsName}促銷倒計時:$hour 小時"
}
}
//具名參數
fun showOnBoard(goodsName:String,showDiscount:(String,Int)->String){
val hour = (1..24).shuffled().last()
println(showDiscount(goodsName,hour))
}
9函數內聯
lambda趨勢可以讓你更靈活的編寫應用,但是,靈活也是要付出代價的。
在JVM上,你定義的lambda會以對象實例的形式存在,JVM會爲所有同lambda打交道的變量分配內存,這就產生了內存開銷。更糟糕的是,lambda的內存開銷會帶來嚴重的性能問題。幸運的是,kotlin有一種優化內存機制叫內聯,有了內聯,JVM就不需要使用lambda對象實例了,因爲避免了變量內存分配。那裏需要使用lambda,編譯器就會將函數體複製黏貼到哪裏。
使用lambda的遞歸函數無法內聯,因爲會導致複製黏貼無限循環,編譯會發出警告。
10函數引用
要把函數作爲參數傳給其他函數使用,除了使用lambda表達式,kotlin還提供了其他方法,傳遞函數引用,函數引用可以把一個具名函數轉換成一個值參,使用lambda表達式的地方,都可以使用函數引用
fun main (){
//要獲得函數引用,使用::操作符,後面跟要引用的函數名。
showOnBoard("衛生紙",::getDiscountWords)
}
fun showOnBoard(goodsName:String,showDiscount:(String,Int)->String){
val hour = (1..24).shuffled().last()
println(showDiscount(goodsName,hour))
}
fun getDiscounWords(goodsName:String,hour:Int):String{
val currentYear = 2027
return "${currentYear}年,雙11${goodsName}促銷倒計時:$hour 小時"
}
11函數類型作爲返回類型
函數類型也是有效的返回類型
fun main(){
val getDiscountWords = configDiscountWords();
println(getDiscountWords("牙膏"))
}
fun configDiscountWords():(String)->String{
val currentYear = 2027
val hout=(1..24),shuffled().last()
return { goodsName:String->
hour +=20
"${currentYear}年,雙11${goodsName}促銷倒計時:${hour}小時"
}
}
12閉包
在kotlin中,匿名函數能夠修改並引用定義在自己作用域之外的變量,匿名函數引用着定義自身的函數裏的變量,Kotlin中的lambda就是閉包
能接受函數或者返回函數的函數又叫高級函數,高級函數廣泛應用於函數式編程當中。
java通過package吧作用於做好了;
kotlin作用域管理通過閉包。
13lambda與匿名內部類
java8支持面向對象編程和lambda表達式,但不支持將函數作爲參數傳給另一個函數或者變量,不過java的替代方案是匿名內部類。
java中做法:
創建了一個藉口、+匿名內部類
kotlin: