連潔
摘要:函數(shù)式編程已經(jīng)成為當(dāng)前最流行的編程模式之一,根據(jù)JAVA8最新標(biāo)準(zhǔn),介紹了lambda表達(dá)式對函數(shù)式編程的支持,并探討了Stream類在應(yīng)用開發(fā)中的使用方式,對lambda表達(dá)式的應(yīng)用模式進(jìn)行了探討。
關(guān)鍵詞:函數(shù)式;Java程序;應(yīng)用
中圖分類號:TP311 文獻(xiàn)標(biāo)識碼:A 文章編號:1009-3044(2015)06-0099-02
函數(shù)式編程(functional programming)作為當(dāng)前最流行的編程規(guī)范之一,主流語言都對其進(jìn)行了支持,作為編程領(lǐng)域最重要的JAVA語言,也在最新的JDK8中新增了相關(guān)特性,這就是lambda(λ)表達(dá)式及Stream類。它使得JAVA語言進(jìn)一步與當(dāng)今流行趨勢結(jié)合,增強(qiáng)了JAVA語言的表現(xiàn)力,拓展了它的應(yīng)用范圍,優(yōu)化了程序的結(jié)構(gòu)與可讀性
1 函數(shù)式編程簡介
函數(shù)式編程(functional programming)是一種編程模式,旨在將運(yùn)算過程盡量寫成一系列嵌套的函數(shù)調(diào)用。在形式上,函數(shù)式編程允許將函數(shù)作為參數(shù)和返回值;在機(jī)制上,函數(shù)式編程在執(zhí)行時(shí)進(jìn)行惰性計(jì)算(lazy evaluation)和閉包等技術(shù)。最主要的優(yōu)點(diǎn)是不修改狀態(tài),可以將任務(wù)隨意分解,很好的符合了當(dāng)前多線程、多處理器編程的趨勢。
2 JAVA中的lambda表達(dá)式
lambda(λ)表達(dá)式是JDK8最大的更新之一,旨在引入函數(shù)式編程思想優(yōu)化JAVA程序。其表達(dá)形式如下:
(int even, int odd) -> even + odd
在JDK8 中,使用->符號引起表達(dá)式,該符號左邊為表達(dá)式的參數(shù),右邊為表達(dá)式的行為。Lambda表達(dá)式可使用在多種場合,例如作為參數(shù)直接傳入某個(gè)函數(shù):
button.addActionListemer(event->System.out.println(“button clicked??!”));
其中button是一個(gè)AWT Button 對象,由此我們可以看出,在傳統(tǒng)的需要匿名內(nèi)部類的地方可由lambda表達(dá)式代替,另外,傳統(tǒng)的函數(shù)參數(shù)需要一個(gè)對象,而引入了lambda表達(dá)式之后,則可以將函數(shù)作為參數(shù)傳入,從而在代碼上更加簡潔。
引入lambda表達(dá)式的優(yōu)點(diǎn)首先體現(xiàn)著對代碼的重構(gòu)上,傳統(tǒng)的JAVA程序有一個(gè)重要的概念即匿名內(nèi)部類,這個(gè)類在某些只使用一次即銷毀的情況下創(chuàng)建,例如常見的為按鈕添加事件
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
System.out.println("button clicked");}
});
但是該代碼當(dāng)中有若干行是純粹的樣板代碼,沒有任何實(shí)際意義,不僅語法冗長,而且破壞了代碼的真實(shí)意圖,而采用lambda表達(dá)式改寫后,該段代碼的目的一目了然,如下所示
button.addActionListener(event->System.out.println("buttonclicked");
其次,lambda表達(dá)式配合jdk8新增的的Stream類可以提高程序——特別是循環(huán)結(jié)構(gòu)——的執(zhí)行效率,在JDK8之前,傳統(tǒng)的循環(huán)結(jié)構(gòu)采用的都是外循環(huán)結(jié)構(gòu),例如試圖取得所有來自北京的教師
int count = 0;
for (Teacher teacher : allTeachers) {
if (teacher.isFrom("London")) {
count++;}
}
可以看到,傳統(tǒng)方式中,集合內(nèi)部的數(shù)據(jù)與外部的循環(huán)語句不停的進(jìn)行交換,外部程序不得不占用一部分空間為結(jié)果集做準(zhǔn)備,從時(shí)間上到空間上都造成了浪費(fèi)。而經(jīng)過lambda表達(dá)式和Stream改造,原有的外部循環(huán)成為內(nèi)部循環(huán),如下例所示:
long count = allArtists.stream().filter(artist -> artist.isFrom("London")).count();
可以看出,使用lambda表達(dá)式后,內(nèi)部循環(huán)只是在符合條件的集合個(gè)體中做出標(biāo)識,不占用額外內(nèi)存,當(dāng)程序不發(fā)出最后的指令(如要求立即返回結(jié)果)時(shí),內(nèi)部循環(huán)不作出任何操作,稱為lazy模式,這樣就節(jié)省了時(shí)間。
3 用lambda表達(dá)式優(yōu)化程序
初學(xué)者在使用lambda表達(dá)式時(shí),可將其應(yīng)用在集合操作中,優(yōu)化其操作方式,lambda表達(dá)式與Stream類所支持的集合優(yōu)化有map、filter、flatmap以及reduce等,下面將詳細(xì)介紹這幾種方式。
在這之前,首先定義一個(gè)領(lǐng)域模型,模仿現(xiàn)實(shí)世界中的某些業(yè)務(wù)需求,這個(gè)領(lǐng)域模型的結(jié)構(gòu)如下
作者Author,包含名稱(String name)、所屬機(jī)構(gòu)(String origine)和若干成員(String [] members )
著作 Book,包含名稱(String name),若干章節(jié)(List chapters)和若干作者(List authors)
章節(jié)Chapter,包含章節(jié)名稱(String name)和字?jǐn)?shù)(int chars)
作者集合authors,著作集合books和章節(jié)集合chapters。
首先來介紹Stream類中的第一種操作,即map操作,該操作負(fù)責(zé)將集合當(dāng)中的元素進(jìn)行符合條件的轉(zhuǎn)換。例如,需要所有作者的所屬機(jī)構(gòu)列表,則使用lambda表達(dá)式和Stream代碼如下:
Listorigines=authors.Stream().map(author->author. getOrigine()).collect(toList());
第二種常用操作是filter操作,旨在篩選出集合當(dāng)中符合條件的元素,例如,需要找到所有成員數(shù)為1的作者(即該作者不是團(tuán)隊(duì)而是個(gè)人),代碼如下
authors.Stream().filter(author->author.getMembers().length<2);
最后一種常用操作為reduce,該操作類似于數(shù)據(jù)庫中的聚合函數(shù),可對結(jié)果進(jìn)行各種統(tǒng)計(jì),如匯總、小計(jì)、總計(jì)等,例如要求計(jì)算所有所有作者全部著作的總字?jǐn)?shù),則代碼可以如下:
chapters.Stream().map(chapter->chapter.getChars()).reduce(0,(base,acc)->base+acc);
以上介紹了函數(shù)式編程在java中的簡單應(yīng)用,作為java8中最重要的新特性,函數(shù)式編程極大的簡化了代碼的編寫,使得java這一語言煥發(fā)了新的生命力,在未來的開發(fā)中,擁有面向?qū)ο蠹懊嫦蚝瘮?shù)雙重特征的java語言必定會發(fā)揮更大的作用。
參考文獻(xiàn):
[1] 張迎周, 張衛(wèi)豐. Haskell:一種現(xiàn)代純函數(shù)式語言[J].南京郵電大學(xué)學(xué)報(bào):自然科學(xué)版,2007(4).
[2] 龐建民, 趙榮彩, 王倩. Haskell語言的惰性計(jì)算特性及其應(yīng)用[J].計(jì)算機(jī)工程與應(yīng)用,2006(10).
[3] Richard Warburton. Java 8 Lambdas: Functional Programming For The Masses[M].ORelly, 2014.