国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Java 8 vs. Scala(二):Stream vs. Collection

GeekGhc / 916人閱讀

摘要:比如對(duì)一個(gè)數(shù)據(jù)流進(jìn)行過(guò)濾映射以及求和運(yùn)算,通過(guò)使用延后機(jī)制,那么所有操作只要遍歷一次,從而減少中間調(diào)用。這里需知道中的元素都是延遲計(jì)算的,正因?yàn)榇?,能夠?jì)算無(wú)限數(shù)據(jù)流。

【編者按】在之前文章中,我們介紹了 Java 8和Scala的Lambda表達(dá)式對(duì)比。在本文,將進(jìn)行 Hussachai Puripunpinyo Java 和 Scala 對(duì)比三部曲的第二部分,主要關(guān)注 Stream 和 Collection,本文由 OneAPM 工程師編譯整理。

首先,為大家做一個(gè)簡(jiǎn)短的介紹,collection 是有限的數(shù)據(jù)集,而 stream 是數(shù)據(jù)的序列集,可以是有限的或無(wú)限的。

Streams API 是 Java 8 中新發(fā)布的 API,主要用于操作 collection 和 streaming 數(shù)據(jù)。Collections API 會(huì)改變數(shù)據(jù)集狀態(tài),而 Streams API 則不會(huì)。例如,當(dāng)你調(diào)用Collections.sort(list)時(shí),該方法會(huì)對(duì)傳入的參數(shù)進(jìn)行排序,而調(diào)用list.stream().sorted() 則會(huì)復(fù)制一份數(shù)據(jù)進(jìn)行操作,保持原數(shù)據(jù)不變。你可以在這里獲得更多關(guān)于 API 數(shù)據(jù)流的信息

以下是筆者從 Java 8 文檔中摘出的 collections 和 streams 之間的比較。強(qiáng)烈建議大家閱讀 完整版。

Streams 和 collections 有以下幾點(diǎn)區(qū)別:

無(wú)存儲(chǔ)。steam 不是存儲(chǔ)數(shù)據(jù)元素的數(shù)據(jù)結(jié)構(gòu)。而是通過(guò)計(jì)算操作管道從源頭傳輸數(shù)據(jù)元素。

2.本質(zhì)是函數(shù)。對(duì) Stream 對(duì)象操作能得到一個(gè)結(jié)果,但是不會(huì)修改原始數(shù)據(jù)。

Laziness-seeking(延遲搜索):Stream 的很多操作如 filter、map、sort 和 duplicate removal(去重)可以延遲實(shí)現(xiàn),意思是我們只要檢查到滿足要求的元素就可以返回。

可能是不受限制的:Streams 允許 Client 取足夠多的元素直到滿足某個(gè)條件為止。而 Collections 不能這么做。

消耗的。Steam 中的元素在 steam 生存期內(nèi)只能被訪問(wèn)一次。

Java 和 Scala 都可以很簡(jiǎn)單地同時(shí)計(jì)算 collection 中的值。在 Java 中,你只需調(diào)用parallelStream()* 或者 stream().parallel(),而不是stream()。在 Scala 中,在調(diào)用其他方法之前,必須先調(diào)用 par()函數(shù)。而且可以通過(guò)添加 parallelism 來(lái)提高程序的性能。不幸的是,大多數(shù)時(shí)間它的執(zhí)行速度都非常慢。事實(shí)上,parallelism 是一個(gè)很容易被誤用的功能。 點(diǎn)這閱讀這有趣的文章

在 JavaDoc 中, parallelStream()方法的介紹是:可能返回一個(gè)并行的 stream(collection作為數(shù)據(jù)源),所以它也可能返回一個(gè)串行 stream。( 有人做過(guò)關(guān)于該API的研究)

圖像標(biāo)題

Java 的 Stream API 是延后執(zhí)行的。這意味著,沒(méi)有指定一個(gè)終結(jié)操作(比如 collect() 方法調(diào)用),那么所有的中間調(diào)用(比如 filter 調(diào)用)是不會(huì)被執(zhí)行的。延遲的流處理主要是為了優(yōu)化 stream API 的執(zhí)行效率。比如對(duì)一個(gè)數(shù)據(jù)流進(jìn)行過(guò)濾、映射以及求和運(yùn)算,通過(guò)使用延后機(jī)制,那么所有操作只要遍歷一次,從而減少中間調(diào)用。同時(shí),延后執(zhí)行允許每個(gè)操作只處理必要的數(shù)據(jù)。相反,Scala 的 collections 是即時(shí)處理的。這樣是否意味著,在測(cè)試中,Java Stream API始終優(yōu)于 Scala ?如果只比較 Java 的 Stream API 和 Scala的 Collection API,那么Java Stream API 的確優(yōu)于 Scala Collection API。但在 Scala 中有更多的選擇。通過(guò)簡(jiǎn)單地調(diào)用toStream(),就可以將一個(gè) Collection 轉(zhuǎn)換成一個(gè) Stream,或者可以使用 view (一種提供延后處理能力的 Collection)來(lái)處理數(shù)據(jù)集合。

下面粗略介紹下 Scala 的 Stream 和 View 特性

Scala 的 Stream

Scala 的 Stream 和 Java 的有所不同。在 Scala Stream 中,無(wú)需調(diào)用終結(jié)操作去取得Stream 的結(jié)果。Stream 是一個(gè)繼承 Abstractseq、 Linearseq和 GenericTraversableTemplate trait的抽象類。所以,你可以把Stream當(dāng)作 SEQ。

如果你不熟悉 Scala,可以將 Seq 當(dāng)作 Java 里的 List。(Scala 中的 List 不是一個(gè)接口)。

這里需知道 Streams 中的元素都是延遲計(jì)算的,正因?yàn)榇?,Stream能夠計(jì)算無(wú)限數(shù)據(jù)流。如果要計(jì)算集合中的所有元素,Stream 和 List 有相同的性能。一旦計(jì)算出結(jié)果,數(shù)值將被緩存。 Stream 有一個(gè) force 函數(shù),能夠強(qiáng)制評(píng)估 stream 再返回結(jié)果。注意,不要在無(wú)限流中調(diào)用該函數(shù),也不要強(qiáng)制該 API 處理整個(gè) stream 的操作,比如 size()、tolist()、foreach() 等,這些操作在 Scala 的 Stream 中都是隱式的。

在 Scala Stream 中實(shí)現(xiàn) Fibonacci 數(shù)列。

def fibFrom(a: Int, b: Int): Stream[Int] = a #:: fibFrom(b, a + b)
val fib1 = fibFrom(0, 1) //0 1 1 2 3 5 8 …
val fib5 = fibFrom(0, 5) //0 5 5 10 15 …
//fib1.force //Don’t do this cause it will call the function infinitely and soon you will get the OutOfMemoryError
//fib1.size //Don’t do this too with the same reason as above.
fib1.take(10) //Do this. It will take the first 10 from the inifite Stream.
fib1.take(20).foreach(println(_)) //Prints 20 first numbers

:: 是 collection 中常用的連接數(shù)據(jù)的方法。而 #:: 表示是連接數(shù)據(jù)但是是延遲執(zhí)行的(Scala中的方法名都很隨意)。

Scala 的 View

再次重申,Scala 的 collection 是一個(gè)嚴(yán)格 collection,而 view 是非嚴(yán)格的。View 是基于一個(gè)基礎(chǔ) collection 的 collection,其中所有的轉(zhuǎn)換都會(huì)延遲執(zhí)行。通過(guò)調(diào)用 view 函數(shù)可以將嚴(yán)格 collection 轉(zhuǎn)換成 view,也可以通過(guò)調(diào)用 force 方法轉(zhuǎn)換回來(lái)。View 并不緩存結(jié)果,每次調(diào)用時(shí)才會(huì)執(zhí)行轉(zhuǎn)換。就像數(shù)據(jù)庫(kù)的 View,但它是虛擬 collection。

創(chuàng)建一個(gè)數(shù)據(jù)集。

public class Pet {
    public static enum Type {
        CAT, DOG
    }
    public static enum Color {
        BLACK, WHITE, BROWN, GREEN
    }
    private String name;
    private Type type;
    private LocalDate birthdate;
    private Color color;
    private int weight;
    ...
}

假設(shè)有一個(gè)寵物集,接下來(lái)會(huì)利用該集合詳細(xì)說(shuō)明。

過(guò)濾器

要求:從集合過(guò)濾一只胖乎乎的寵物,胖乎乎的定義是體重超過(guò) 50 磅,還想得到一個(gè)在 2013年1月1日出生的寵物名單。下面的代碼片段顯示了如何以不同的方式實(shí)現(xiàn)該濾波器的工作。

Java 方法1:傳統(tǒng)方式

//Before Java 8
List tmpList = new ArrayList<>();
for(Pet pet: pets){
    if(pet.getBirthdate().isBefore(LocalDate.of(2013, Month.JANUARY, 1))
            && pet.getWeight() > 50){
        tmpList.add(pet);
    }
}

這種方式在命令式語(yǔ)言中十分常見(jiàn)。首先,必須創(chuàng)建一個(gè)臨時(shí)集合,然后遍歷所有元素,存儲(chǔ)滿足條件的元素到臨時(shí)集中。的確有點(diǎn)繞口,但其結(jié)果和效率都非常不錯(cuò)。但本人不得不掃興地說(shuō),傳統(tǒng)方法比 Streams API 更快。不過(guò),完全不用擔(dān)心性能問(wèn)題,因?yàn)榇a的簡(jiǎn)潔比輕微的性能增益更重要。

Java 方法2:Streams API

//Java 8 - Stream
pets.stream()
    .filter(pet -> pet.getBirthdate().isBefore(LocalDate.of(2013,   Month.JANUARY, 1)))
    .filter(pet -> pet.getWeight() > 50)
    .collect(toList())

以上代碼表示,使用 Streams API 過(guò)濾集合中的元素。之所以故意兩次調(diào)用過(guò)濾函數(shù),是想表明 Streams 的 API 設(shè)計(jì)就像一個(gè) Builder pattern。在 Builder pattern 調(diào)用構(gòu)建方法之前,可以將各種方法串聯(lián)起來(lái)。在 Streams API 中,構(gòu)建方法被稱為終結(jié)操作,非終結(jié)操作的叫做中間操作。終結(jié)操作可能不同于構(gòu)造函數(shù),因?yàn)樗?Streams API 中只能被調(diào)用一次。但還有很多可使用的終結(jié)操作,比如 collect、count、min、max、iterator、toArray。這些操作會(huì)產(chǎn)生結(jié)果,而終端操作會(huì)消耗值,例如 forEach。那么,你認(rèn)為傳統(tǒng)方法和 Streams API 哪一個(gè)的可讀性更強(qiáng)?

Java 方法3:Collections API

//Java 8 - Collection
pets.removeIf(pet -> !(pet.getBirthdate().isBefore(LocalDate.of(2013,Month.JANUARY, 1))
                && pet.getWeight() > 50));
//Applying De-Morgan"s law.
pets.removeIf(pet -> pets.get(0).getBirthdate().toEpochDay() >= LocalDate.of(2013, Month.JANUARY, 1).toEpochDay()
                || pet.getWeight() <= 50);

這種方法是最簡(jiǎn)短的。但是,它修改了原始集合,而前面的方法不會(huì)。removeif 函數(shù)將Predicate(函數(shù)接口)作為參數(shù)。Predicate 是一個(gè)行為參數(shù),它只有一個(gè)名為 test 抽象方法,只需要一個(gè)對(duì)象并返回布爾值。注意,這里必須使用“!”取反,或者可以應(yīng)用 De Morgan 定理,使得代碼看起來(lái)像二次聲明。

Scala 方法:Collection、View和Stream

//Scala - strict collection
pets.filter { pet => pet.getBirthdate.isBefore(LocalDate.of(2013, Month.JANUARY, 1))}
.filter { pet => pet.getWeight > 50 } //List[Pet]
//Scala - non-strict collection
pets.views.filter { pet => pet.getBirthdate.isBefore(LocalDate.of(2013, Month.JANUARY, 1))}
.filter { pet => pet.getWeight > 50 } //SeqView[Pet]
//Scala - stream
pets.toStream.filter { pet => pet.getBirthdate.isBefore(LocalDate.of(2013,  Month.JANUARY, 1))}
.filter { pet => pet.getWeight > 50 } //Stream[Pet]

Scala 的解決方案類似于 Java 的 Streams API。但首先,必須調(diào)用 view 函數(shù)把嚴(yán)格集轉(zhuǎn)向非嚴(yán)格集,然后再用 tostream 函數(shù)把嚴(yán)格集轉(zhuǎn)成一個(gè) stream。

接下來(lái)直接上代碼。

分組

通過(guò)元素的一個(gè)屬性對(duì)起所在集合做 group。結(jié)果是 Map,其中T是一個(gè)泛型類型。

要求:通過(guò)類型對(duì)寵物分組,諸如狗,貓等等。

注意:groupingBy 是 java.util.stream.Collectors 的靜態(tài)的 helper method。

排序

根據(jù)屬性對(duì)集合中的元素排序。結(jié)果會(huì)是任何類型的集合,根據(jù)配置來(lái)維持元素順序。

要求:需按照類型、名字和顏色排序。

映射

將給定函數(shù)應(yīng)用在集合元素中。根據(jù)定義的函數(shù)不同,其返回的結(jié)果類型也不同。

要求:需將寵物轉(zhuǎn)化成字符串,以%s?—?name: %s, color: %s的格式。

尋找第一個(gè)

返回第一個(gè)能與指定 predicate 匹配的值。

要求:找一個(gè)名為Handsome的寵物。無(wú)論有多少個(gè)Handsome,只取第一個(gè)。

這個(gè)問(wèn)題有點(diǎn)棘手。不知道你是否注意,在 Scala 中筆者所使用的是 find 函數(shù)而不是 filter ?如果用 filter 代替 find,它就會(huì)計(jì)算集合中所有元素,因?yàn)?scala collection 是嚴(yán)格的。但是,在 Java 的 Streams API 中你可以放心使用 filter,因?yàn)樗鼤?huì)計(jì)算需要的第一個(gè)值,并不會(huì)計(jì)算所有元素。這就是延遲執(zhí)行的好處!

接下來(lái),向大家介紹 scala 中更多集合延遲執(zhí)行的實(shí)例。我們假定 filter 總是返回 true,然后再取第二個(gè)值。將會(huì)是什么結(jié)果呢?

pets.filter { x => println(x.getName); true }.get(1) --- (1)
pets.toStream.filter { x => println(x.getName); true }.get(1) -- (2)

如上所示,(1)式將會(huì)打印出集合中所有寵物的名字,而(2)式則只輸出前2個(gè)寵物的名字。這就是 lazy collection 的好處,總是延遲計(jì)算。

pets.view.filter { x => println(x.getName); true }.get(1) --- (3)

(3)式和(2)式會(huì)有一樣的結(jié)果嗎?錯(cuò)!它的結(jié)果和(1)是一樣的,你知道為什么嗎?

通過(guò)比較 Java 和 Scala 中的一些共同的操作方法 ——filter、group、map 和 find;很明顯 Scala 的方法比 Java 更簡(jiǎn)潔。你更喜歡哪一個(gè)呢?哪一個(gè)的可讀性更強(qiáng)?

在文章的下一個(gè)部分,我們將比較哪種方式更快。敬請(qǐng)期待!

原文鏈接: https://dzone.com/articles/java-8-vs-scalapart-ii-streams-api

OneAPM for Java 能夠深入到所有 Java 應(yīng)用內(nèi)部完成應(yīng)用性能管理和監(jiān)控,包括代碼級(jí)別性能問(wèn)題的可見(jiàn)性、性能瓶頸的快速識(shí)別與追溯、真實(shí)用戶體驗(yàn)監(jiān)控、服務(wù)器監(jiān)控和端到端的應(yīng)用性能管理。想閱讀更多技術(shù)文章,請(qǐng)?jiān)L問(wèn) OneAPM 官方博客。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/64767.html

相關(guān)文章

  • Java 8 vs. Scala(一): Lambda表達(dá)式

    摘要:編程語(yǔ)言將函數(shù)作為一等公民,函數(shù)可以被作為參數(shù)或者返回值傳遞,因?yàn)樗灰暈閷?duì)象。是表示已注釋接口是函數(shù)接口的注釋。如果一個(gè)函數(shù)有一個(gè)或多個(gè)參數(shù)并且有返回值呢為了解決這個(gè)問(wèn)題,提供了一系列通用函數(shù)接口,在包里。 【編者按】雖然 Java 深得大量開(kāi)發(fā)者喜愛(ài),但是對(duì)比其他現(xiàn)代編程語(yǔ)言,其語(yǔ)法確實(shí)略顯冗長(zhǎng)。但是通過(guò) Java8,直接利用 lambda 表達(dá)式就能編寫(xiě)出既可讀又簡(jiǎn)潔的代碼。作者...

    yuanxin 評(píng)論0 收藏0
  • Java 8怎么了:局部套用vs閉包

    摘要:本文主要介紹了中的閉包與局部套用功能,由國(guó)內(nèi)管理平臺(tái)編譯呈現(xiàn)。譬如,認(rèn)為給帶來(lái)了閉包特性就是其中之一。但是首先,我們將考慮如何利用閉包進(jìn)行實(shí)現(xiàn)。很顯然,閉包打破了這一準(zhǔn)則。這就是局部調(diào)用,它總是比閉包更為穩(wěn)妥。 【編者按】本文作者為專注于自然語(yǔ)言處理多年的 Pierre-Yves Saumont,Pierre-Yves 著有30多本主講 Java 軟件開(kāi)發(fā)的書(shū)籍,自2008開(kāi)始供職于 ...

    3fuyu 評(píng)論0 收藏0
  • Java8新特性第3章(Stream API)

    摘要:另外,像這樣生成值的操作和這樣產(chǎn)生副作用的操作都是天然急性求值,因?yàn)樗鼈儽仨氁a(chǎn)生具體的結(jié)果。這樣可以大大減少維持中間結(jié)果所帶來(lái)的開(kāi)銷?,F(xiàn)在我們需要篩選出含有平米以上房源的小區(qū),并按照小區(qū)名排序。 轉(zhuǎn)載請(qǐng)注明出處:https://zhuanlan.zhihu.com/p/20540202 Stream作為Java8的新特性之一,他與Java IO包中的InputStream和Outp...

    andycall 評(píng)論0 收藏0
  • JVM 平臺(tái)上的各種語(yǔ)言的開(kāi)發(fā)指南[z]

    摘要:我們的目標(biāo)是建立對(duì)每一種語(yǔ)言的認(rèn)識(shí),它們是如何進(jìn)化的,未來(lái)將走向何方。有點(diǎn)的味道是堅(jiān)持使用動(dòng)態(tài)類型,但唯一還收到合理?yè)肀玫木幊陶Z(yǔ)言,然而一些在企業(yè)的大型團(tuán)隊(duì)中工作的開(kāi)發(fā)者擇認(rèn)為這會(huì)是的一個(gè)缺陷。 為什么我們需要如此多的JVM語(yǔ)言? 在2013年你可以有50中JVM語(yǔ)言的選擇來(lái)用于你的下一個(gè)項(xiàng)目。盡管你可以說(shuō)出一大打的名字,你會(huì)準(zhǔn)備為你的下一個(gè)項(xiàng)目選擇一種新的JVM語(yǔ)言么? 如今借助來(lái)自...

    phodal 評(píng)論0 收藏0
  • 轉(zhuǎn) | Java8初體驗(yàn)(一)lambda表達(dá)式語(yǔ)法

    摘要:初體驗(yàn)下面進(jìn)入本文的正題表達(dá)式。接下來(lái)展示表達(dá)式和其好基友的配合。吐槽一下方法引用表面上看起來(lái)方法引用和構(gòu)造器引用進(jìn)一步簡(jiǎn)化了表達(dá)式的書(shū)寫(xiě),但是個(gè)人覺(jué)得這方面沒(méi)有的下劃線語(yǔ)法更加通用。 感謝同事【天錦】的投稿。投稿請(qǐng)聯(lián)系 tengfei@ifeve.com 本文主要記錄自己學(xué)習(xí)Java8的歷程,方便大家一起探討和自己的備忘。因?yàn)楸救艘彩莿倓傞_(kāi)始學(xué)習(xí)Java8,所以文中肯定有錯(cuò)誤和理解偏...

    Lucky_Boy 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<