Java 8給Java帶來了一場變革。很明顯,這個版本是過去十年以來推出的最具份量的Java更新,其中囊括了海量新特性,包括默認(rèn)方法、方法與構(gòu)造函數(shù)引用以及Lambda函數(shù)等等。
其中最有趣的一項特性當(dāng)數(shù)全新java.util.streamAPI,它作為Javadoc狀態(tài)存在,能夠?qū)υ亓鬟M(jìn)行函數(shù)式操作,例如在集合中進(jìn)行map-reduce變換。
將這個新API與Lambda表達(dá)式相結(jié)合,我們就得到了一條簡潔但卻強大的語法,能夠?qū)?yīng)用程序中的代碼進(jìn)行大幅簡化。1
將這個新API與Lambda表達(dá)式相結(jié)合,我們就得到了一條簡潔但卻強大的語法,能夠?qū)?yīng)用程序中的代碼進(jìn)行大幅簡化。
就以表面上看起來相當(dāng)簡單的集合過濾任務(wù)為例。在這一實例中,我們?nèi)缦滤緞?chuàng)建Message Collection type:
創(chuàng)建一個Messages Collection
List messages = new ArrayList(); messages.add(new Message("aglover", "foo", 56854)); messages.add(new Message("aglover", "foo", 85)); messages.add(new Message("aglover", "bar", 9999)); messages.add(new Message("rsmith", "foo", 4564));
在這個集合中,我打算將delay(第三個構(gòu)造函數(shù)參數(shù))在3000秒以上作為條件對Message進(jìn)行全面過濾。在Java 8之前的版本中,大家可以用以下方式表達(dá)這類邏輯:
傳統(tǒng)過濾方式
for (Message message : messages)
if (message.delay > 3000)
System.outln(message);
不過在Java 8中,這項工作將變得更加簡單明了。集合如今支持stream方法,它能夠?qū)⒌讓訑?shù)據(jù)結(jié)構(gòu)轉(zhuǎn)化為可重復(fù)的對象流,從而實現(xiàn)使用Lambda表達(dá)式的全新函數(shù)式操作。大多數(shù)此類操作都可以被串連起來。這些可串連方法被稱為intermediate,那些無法被串連的方法則被表示為terminal。
簡要來講,Lambda表達(dá)式與匿名類基本相似,只不過摒棄了大量語法限制。舉例來說,如果大家在查看Javadoc以尋找Stream中filter方法的對應(yīng)參數(shù),各位會發(fā)現(xiàn)它擁有一個Predicate type。不過我們不需要像在Java 8之前的版本中那樣利用匿名類來實現(xiàn)這一對接。因此,Predicate Lambda表達(dá)式能夠過濾掉所有數(shù)值高于3000的條目,如下所示:
Lambda表達(dá)式
x -> x.delay > 3000
其中的x正是被傳送至集合流內(nèi)每一個值的參數(shù),而->符號右側(cè)的所有內(nèi)容都作為表達(dá)式估值。將這些結(jié)合起來,就成了Java 8中的處理方式:
Lambda表達(dá)式流
messages.stream().filter(m -> m.delay > 3000).forEach(item -> System.outln(item));
有趣的是,由于Java 8中的其它一些新特性,我們還可以對forEach的Lambda表達(dá)式進(jìn)行進(jìn)一步簡化:
Lambda表達(dá)式流還能進(jìn)一步簡化
messages.stream().filter(m -> m.delay > 3000).forEach(System.out::println);
由于forEach Lambda表達(dá)式的參數(shù)僅僅單純作用于println,Java 8現(xiàn)在允許我們直接對參數(shù)進(jìn)行整體對接。
之前我曾經(jīng)提到過,集合流允許大家將各個Lambda表達(dá)式串連起來—在上面的例子中,filter方法屬于一項intermediate方法,而forEach則是一項terminal方法。其它能夠為函數(shù)程序員快速識別出的intermediate方法還包括:map、flatMap以及reduce等,這里就不一一列舉了。
具體來講,我希望找到Message當(dāng)中所有延遲周期超過3000秒的條目并計算它們的總計延遲時長。如果沒有函數(shù)魔法作為輔助,我只能如下進(jìn)行:
普通Java寫法
long totalWaitTime = 0; for (Message message : messages)
if (message.delay > 3000)
totalWaitTime += message.delay;
然而隨著Java 8的面世與大量新函數(shù)的出現(xiàn),大家可以實現(xiàn)更為精致的代碼結(jié)構(gòu),具體如下:
文藝Java 8寫法
long totWaitTime = messages.stream().filter(m -> m.delay > 3000).mapToLong(m -> m.delay).sum();
請注意我將filter與mapToLong方法進(jìn)行串連的方式,再加上一條terminal sum。順便說一句,sum方法需要使用一種特殊的映射方法類型才能產(chǎn)生原始type集合,例如mapToLong以及mapToInt等等。
函數(shù)式編程作為一大核心語言特性,能夠為開發(fā)者帶來令人嘆為觀止的強大構(gòu)建能力。雖然大部分此類技術(shù)已經(jīng)能夠在各類第三方庫(例如Guava)以及JVM語言(例如Scala與Groovy)中找到,但將這些關(guān)鍵特性融入Java仍然能夠吸引更為廣泛的開發(fā)者受眾、并給未來的開發(fā)前景帶來深遠(yuǎn)影響。
毫無疑問,Java 8的出現(xiàn)讓Java在通往完美的道路上再度邁出一大步。