lambda表達式與Kotlin高階函數(shù)

lambda表達式與Kotlin高階函數(shù)

概念

lambda表達式囊咏,或者簡稱為lambda目代,本質(zhì)上就是可以傳遞給其他函數(shù)的一小段代碼濒蒋。可以輕松地把通用代碼結(jié)構(gòu)抽取成庫函數(shù)楼誓。
高階函數(shù)就是以另一個函數(shù)最為參數(shù)或者返回值的函數(shù)玉锌。在kotlin中,函數(shù)可以用lambda或者函數(shù)引用來表示疟羹。因此主守,任何以lambda或者函數(shù)引用作為參數(shù)或返回值的函數(shù)都是高階函數(shù)禀倔。

lambda

java 8的新特性之一就是引入lambda表達式。函數(shù)式編程特供了一種解決問題的方法:把函數(shù)當做值來對待参淫【群可以直接傳遞函數(shù),而不需要先聲明一個類再傳遞這個類的實例(這種場景常出現(xiàn)在java匿名內(nèi)部類實現(xiàn)接口回調(diào))涎才。高效且直接的傳遞代碼塊使得代碼更加簡潔捎谨。
我們來看一個例子,定義一個按鈕的點擊事件憔维。
使用匿名內(nèi)部類的方式實現(xiàn):

button.setOnClickListener(new OnCLickListener(){
    @Override
    public void onCLick(View view){
        doSomething();
    }
});

而在kotlin和java 8中,可以使用lambda實現(xiàn):

button.setOnClickListener{           
    doSomething()
}

這兩段代碼做的事情一模一樣畏邢,但是后者更簡潔易讀业扒。

lambda表達式的語法

一個lambda把一小段行為進行編碼,可以將它當做一個值傳遞舒萎〕檀ⅲ可以被獨立的聲明并存儲到一個變量中。
聲明lambda表達式的語法如下:

{x:Int,y:Int -> x+y}

kotlin的lambda表達式始終用花括號包圍臂寝,箭頭把實參列表和lambda的函數(shù)體隔開章鲤。箭頭前為參數(shù),箭頭后為函數(shù)體咆贬。
接下來我們看一下lambda的使用败徊。

lambda表達式的使用

假設存在一個高階函數(shù),該函數(shù)接受一個入?yún)閮蓚€Int類型的數(shù)據(jù)掏缎,返回值也為int類型的函數(shù)皱蹦,并返回一個int類型的數(shù)據(jù),該數(shù)據(jù)為傳入函數(shù)對2和3的某種運算結(jié)果眷蜈,代碼如下:

private fun lambdaFunction  (function:(Int, Int)->Int):Int{
        return function(2,3)
    }

如果我們要計算2和3的和沪哺,則可以這樣調(diào)用:

lambdaFunction({x:Int,y:Int -> x+y})

但這段代碼多少有點啰嗦,過多的符號破壞了代碼的可讀性酌儒,幸運的是和局部變量一樣如果lambda參數(shù)的類型可以被推導出來辜妓,無需顯式地指定它,那么代碼可以精簡為:

lambdaFunction({x,y -> x+y})

其次忌怎,若lambda表達式是函數(shù)調(diào)動的最后一個實參籍滴,它可以放在花括號外面,繼續(xù)改進代碼:

lambdaFunction(){x,y -> x+y}

最后榴啸,當lambda是函數(shù)唯一的實參時异逐,還可以去掉代碼中的空括號對,那么最后精簡的代碼為:

lambdaFunction{x,y -> x+y}

上述四種語法形式含義都是一樣的插掂,但最后一種更易讀
同時灰瞻,如果當前上下文期望的是只有一個參數(shù)的lambda且這個參數(shù)的類型可以推導出來腥例,則可以使用默認參數(shù)名稱it指代命名參數(shù)。例如

user.let{
    it.age
}

其中it指代入?yún)iew酝润,注意it約定能大大縮短代碼燎竖,但不能濫用。尤其是在嵌套的情況下要销,最好顯示的聲明每個lambda參數(shù)
接下來我們談談和lambda形影不離的概念:從上下文中捕捉變量

在作用域中訪問變量

首先构回,看一段java代碼:

private void fun(User me) {
        int a = 100;
        new Runnable() {
            @Override
            public void run() {
                me.setAge(a);
            }
        };
    }

在函數(shù)內(nèi)聲明一個匿名內(nèi)部類的時候,能夠在這個匿名內(nèi)部類中引用這個函數(shù)的參數(shù)和局部變量(需要注意的是:在JDK8之前疏咐,如果我們在匿名內(nèi)部類中需要訪問局部變量纤掸,那么這個局部變量必須用final修飾符修飾)。lambda表達式可以做同樣的事情浑塞。我們使用forEach來展示這種行為:

private fun lambdaFunction  (list: List<User>,age: Int){
        list.forEach { 
            it.age = age
        }
    }

這種從lambda內(nèi)部訪問外部變量的行為借跪,我們稱這些變量被lambda捕捉。
至此酌壕,lambda表達式已基本介紹完畢掏愁,接下來介紹kotlin中的高階函數(shù):

高階函數(shù)

回顧一下開篇講的高階函數(shù)定義:

高階函數(shù)就是以另一個函數(shù)最為參數(shù)或者返回值的函數(shù)。在kotlin中卵牍,函數(shù)可以用lambda或者函數(shù)引用來表示果港。因此,任何以lambda或者函數(shù)引用作為參數(shù)或返回值的函數(shù)都是高階函數(shù)

通過定義可以看出糊昙,其實在前文中使用到的lambdaFunction便是一個高階函數(shù)辛掠。在聲明一個高階函數(shù)之前,首先必須要知道什么是函數(shù)類型

函數(shù)類型

回顧lambdaFunction函數(shù):

private fun lambdaFunction  (function:(Int, Int)->Int):Int{
        return function(2,3)
    }

其中释牺,(Int, Int)->Int聲明了一個函數(shù)類型公浪。函數(shù)類型包括參數(shù)類型和返回類型,使用->箭頭講參數(shù)類型和返回類型分隔船侧。
需要注意的是:Unit類型用于表達函數(shù)不返回任何有用的值欠气,在聲明一個普通函數(shù)時可以省略,但是在一個函數(shù)類型的聲明過程中總是需要一個顯式的返回值镜撩,所以预柒,在這種場景下Unit不可省略

(Int, Int)->Unit

同時,在lambda表達式{x,y -> x+y}中參數(shù)的類型是被省略的袁梗,因為它們的類型已經(jīng)在函數(shù)類型的參數(shù)類型中指定了宜鸯,所以無需在lambda本身定義中再次聲明。
可以為函數(shù)類型聲明中的參數(shù)指定名稱:
(a:Int, b:Int)->Int遮怜,其對應的lambda表達式可以為:

{x,y -> x+y}
//或者
{a,b-> a+b}

參數(shù)名稱不會影響類型的匹配淋袖,當聲明一個lambda時,可以使用任意符合規(guī)則的名稱锯梁,但命名會提升代碼的可讀性即碗。

入?yún)楹瘮?shù)的函數(shù)

知道了聲明一個高階函數(shù)的方法之后焰情,接下來就是去實現(xiàn)它。繼續(xù)以lambdaFunction作為例子剥懒,它的代碼如下:

private fun lambdaFunction  (function:(Int, Int)->Int):Int{
        return function(2,3)
}

使用方法為:

//計算2和3的乘級
lambdaFunction{x,y -> x*y}
//計算2和3的和
lambdaFunction{x,y -> x+y}

調(diào)用作為參數(shù)的函數(shù)和調(diào)用普通函數(shù)一樣内舟,如lambdaFunction中調(diào)用function
這其中的原理為:

函數(shù)類型被聲明為普通的接口:一個函數(shù)類型的變量是FunctionN接口的一個實現(xiàn),每個接口定義了一個invoke方法沒調(diào)用這個方法就會執(zhí)行函數(shù)初橘。一個函數(shù)類型的變量就是實現(xiàn)了對應FunctionN接口的實現(xiàn)類的實例验游,實現(xiàn)類的invoke方法包含了lambda函數(shù)體。

返回值為函數(shù)的函數(shù)

從函數(shù)中返回一個函數(shù)并沒有將函數(shù)作為參數(shù)進行傳遞那么有用保檐。但在程序中的一段邏輯可能因為其他條件而發(fā)生變化耕蝉,便是其大顯身手的時機。依舊以乘法和加法舉例:

private fun lambdaFunction  (a:Int):(a:Int,b: Int)->Int{
        if (a>0){
            return {a, b -> a*b}
        } else{
            return {a, b -> a+b}
        }
    }
lambdaFunction(2)(1,2)
val lam = lambdaFunction(0)
lam(1,2)

函數(shù)lambdaFunction根據(jù)入?yún)的值分別返回求和以及求積函數(shù)夜只。其中垒在,函數(shù)的返回值為(a:Int,b: Int)->Int,聲明一個返回一個函數(shù)的函數(shù),需要指定一個函數(shù)類型作為返回類型盐肃。

總結(jié)

至此,大家對Kotlin高階函數(shù)與lambda表達式應該有了清晰的認識权悟。但本文只作為高階函數(shù)和lambda使用的入門教程砸王,尚未解釋lambda表達式會被編譯成匿名類,以及由此引出的內(nèi)聯(lián)函數(shù)峦阁,也未涉及到高階函數(shù)中的控制流和集合函數(shù)式API谦铃。欲了解相關知識,請持續(xù)關注作者博客榔昔。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末驹闰,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子撒会,更是在濱河造成了極大的恐慌嘹朗,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件诵肛,死亡現(xiàn)場離奇詭異屹培,居然都是意外死亡,警方通過查閱死者的電腦和手機怔檩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進店門褪秀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人薛训,你說我怎么就攤上這事媒吗。” “怎么了乙埃?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵闸英,是天一觀的道長锯岖。 經(jīng)常有香客問我,道長自阱,這世上最難降的妖魔是什么嚎莉? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮沛豌,結(jié)果婚禮上趋箩,老公的妹妹穿的比我還像新娘。我一直安慰自己加派,他們只是感情好叫确,可當我...
    茶點故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著芍锦,像睡著了一般竹勉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上娄琉,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天次乓,我揣著相機與錄音,去河邊找鬼孽水。 笑死票腰,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的女气。 我是一名探鬼主播杏慰,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼炼鞠!你這毒婦竟也來了缘滥?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤谒主,失蹤者是張志新(化名)和其女友劉穎朝扼,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體霎肯,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡吟税,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了姿现。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片肠仪。...
    茶點故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖备典,靈堂內(nèi)的尸體忽然破棺而出异旧,到底是詐尸還是另有隱情,我是刑警寧澤提佣,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布吮蛹,位于F島的核電站荤崇,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏潮针。R本人自食惡果不足惜术荤,卻給世界環(huán)境...
    茶點故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望每篷。 院中可真熱鬧瓣戚,春花似錦、人聲如沸焦读。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽矗晃。三九已至仑嗅,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間张症,已是汗流浹背仓技。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留俗他,地道東北人脖捻。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像拯辙,于是被迫代替她去往敵國和親郭变。 傳聞我的和親對象是個殘疾皇子颜价,可洞房花燭夜當晚...
    茶點故事閱讀 43,490評論 2 348

推薦閱讀更多精彩內(nèi)容