Lambda表達(dá)式
經(jīng)常聽到一個概念:閉包。閉包就是能夠讀取其他函數(shù)內(nèi)部變量的函數(shù)。例如在javascript中,只有函數(shù)內(nèi)部的子函數(shù)才能讀取局部變量,所以閉包可以理解成“定義在一個函數(shù)內(nèi)部的函數(shù)“。在本質(zhì)上,閉包是將函數(shù)內(nèi)部和函數(shù)外部連接起來的橋梁。
其實(shí),就是Lambda表達(dá)式,Lambda 允許把函數(shù)作為一個方法的參數(shù)(函數(shù)作為參數(shù)傳遞進(jìn)方法中)。
出現(xiàn)原因
面向?qū)ο笫骄幊叹蛻?yīng)該純粹的面向?qū)ο?,于是?jīng)??吹竭@樣的寫法: 如果你想寫一個方法,那么就必須把它放到一個類里面,然后new出來對象,對象調(diào)用這個方法。最大的問題就在于其冗余的語法,有人戲稱匿名類型導(dǎo)致了“高度問題”(height problem): 大多匿名內(nèi)部類的多行代碼中僅有一行在做實(shí)際工作。因此JAVA8中就提供了這種“函數(shù)式編程”的方法 —— lambda表達(dá)式,供我們來更加簡明扼要的實(shí)現(xiàn)內(nèi)部匿名類的功能。
也就是說,你在某處就真的只需要一個能做一件事情的函數(shù)而已,連它叫什么名字都無關(guān)緊要。 Lambda 表達(dá)式就可以用來做這件事。
語法介紹
函數(shù)式接口
函數(shù)式接口(Functional Interface):定義的一個接口,接口里面必須 有且只有一個抽象方法(可以有默認(rèn)方法和靜態(tài)方法) ,這樣的接口就成為函數(shù)式接口。在可以使用lambda表達(dá)式的地方,方法聲明時必須包含一個函數(shù)式的接口。
如果我們提供的這個接口包含一個以上的Abstract Method,那么使用lambda表達(dá)式則會報錯。 因為這不是函數(shù)式接口。
例如:
Java 8為函數(shù)式接口引入了一個新注解@FunctionalInterface,主要用于編譯級錯誤檢查,加上該注解,當(dāng)你寫的接口不符合函數(shù)式接口定義的時候,編譯器會報錯。你不加的話,就不做檢查。
注意點(diǎn):
函數(shù)式接口中可以額外定義多個Object的public方法一樣抽象方法:接口最終有確定的類實(shí)現(xiàn), 而類的最終父類是Object。 因此函數(shù)式接口可以定義Object的public方法。
函數(shù)式接口的抽象方法可以聲明 可檢查異常(checked exception)。 在調(diào)用目標(biāo)對象的這個方法時必須catch這個異常。
函數(shù)式接口中除了那個抽象方法外還可以包含靜態(tài)方法、默認(rèn)方法。
任何函數(shù)式接口都可以使用lambda表達(dá)式替換。 例如系統(tǒng)已經(jīng)有的:ActionListener、Comparator、Runnable。JDK 8之前已有的函數(shù)式接口:
另外,還有好多好多的接口,可以到具體的java.util.function包下去看一下。
那么在參數(shù)為這些接口的地方,我們就可以直接使用lambda表達(dá)式了!
Lambda表達(dá)式
當(dāng)lambda表達(dá)式的參數(shù)個數(shù)只有一個,可以省略小括號;
當(dāng)lambda表達(dá)式只包含一條語句時,可以省略大括號、return和語句結(jié)尾的分號。自動返回該語句的結(jié)果。
Lambda 表達(dá)式的簡單例子:
特性與注意點(diǎn)
lambda表達(dá)式中的this概念
在lambda中,this不是指向lambda表達(dá)式產(chǎn)生的那個SAM對象,而是聲明它的外部對象。
不舉例子了,是真的。
類型推導(dǎo)
先上個小例子舉例:
編譯器負(fù)責(zé)推導(dǎo)lambda表達(dá)式的類型。它利用lambda表達(dá)式所在上下文所期待的類型進(jìn)行推導(dǎo), 這個被期待的類型被稱為目標(biāo)類型。就是說我們傳入的參數(shù)可以無需寫類型了!
因此,在定義函數(shù)時:
MathOperation addition = (a, b) -> a + b;
我們并沒有在入?yún)⒗镎f明入?yún),b的類型,因為如果沒有類型推導(dǎo),得這么寫:
(int a, int b) -> a + b;
2.3.3 函數(shù)嵌套
我們知道,系統(tǒng)已經(jīng)幫我們創(chuàng)建了幾個函數(shù)時接口,例如:
它的代碼如下:
它內(nèi)置了兩個寫出了默認(rèn)實(shí)現(xiàn)的方法,基于它們,可以實(shí)現(xiàn)函數(shù)的嵌套。
首先,這是一個函數(shù)式接口,真正的抽象函數(shù)只有一個。
接下來我們看一下,compose() 和 andThen() 這兩個默認(rèn)實(shí)現(xiàn)為什么能夠?qū)崿F(xiàn)級聯(lián)操作:首先我們定義了兩個,分別是fun1和fun2。那,對于fun1.apply("a")操作,我們就是將“a”作為參數(shù),傳給函數(shù)fun1,然后fun1把它執(zhí)行掉,故輸出“a>”。
我們著重要分析的是fun1.compose(fun2).apply("b")。分析compose函數(shù),before=fun2。因此,(V v) -> apply(before.apply(v))最終變?yōu)椋?V v) -> apply(fun2.apply(v)),即為:fun1.apply(fun2.apply(v)),因此是v先給fun2處理,得到“b+”;然后“b+”傳給fun1,得到“b+>”。因此,實(shí)現(xiàn)了兩個函數(shù)的嵌套。
同理,fun1.andThen(fun2).apply("c"),after=fun2,因此(T t) -> after.apply(apply(t));即為:fun2.apply(apply(t))。apply(t)是針對于fun1的,因此是fun1處理完完后又fun2處理。
不過,這兩個方法是系統(tǒng)內(nèi)置的,會用就可以了。
3 總結(jié)
Java8 提供的Lambda表達(dá)式使得Java程序更為便捷、靈活,不過在使用Lambda表達(dá)式時也要注意相關(guān)指向問題,防止迷失。
關(guān)于Java8中Lambda表達(dá)式的介紹就到這里,在后續(xù)的文章中我們將介紹Java8中的其它特性。
以上就是長沙牛耳教育Java培訓(xùn)機(jī)構(gòu)小編介紹的“Java中什么是lambda表達(dá)式”的內(nèi)容,希望對大家有幫助,如有疑問,請在線咨詢,有專業(yè)老師隨時為你服務(wù)。