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