成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

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

GeekGhc / 932人閱讀

摘要:比如對一個數據流進行過濾映射以及求和運算,通過使用延后機制,那么所有操作只要遍歷一次,從而減少中間調用。這里需知道中的元素都是延遲計算的,正因為此,能夠計算無限數據流。

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

首先,為大家做一個簡短的介紹,collection 是有限的數據集,而 stream 是數據的序列集,可以是有限的或無限的。

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

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

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

無存儲。steam 不是存儲數據元素的數據結構。而是通過計算操作管道從源頭傳輸數據元素。

2.本質是函數。對 Stream 對象操作能得到一個結果,但是不會修改原始數據。

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

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

消耗的。Steam 中的元素在 steam 生存期內只能被訪問一次。

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

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

圖像標題

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

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

Scala 的 Stream

Scala 的 Stream 和 Java 的有所不同。在 Scala Stream 中,無需調用終結操作去取得Stream 的結果。Stream 是一個繼承 Abstractseq、 Linearseq和 GenericTraversableTemplate trait的抽象類。所以,你可以把Stream當作 SEQ。

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

這里需知道 Streams 中的元素都是延遲計算的,正因為此,Stream能夠計算無限數據流。如果要計算集合中的所有元素,Stream 和 List 有相同的性能。一旦計算出結果,數值將被緩存。 Stream 有一個 force 函數,能夠強制評估 stream 再返回結果。注意,不要在無限流中調用該函數,也不要強制該 API 處理整個 stream 的操作,比如 size()、tolist()、foreach() 等,這些操作在 Scala 的 Stream 中都是隱式的。

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

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 中常用的連接數據的方法。而 #:: 表示是連接數據但是是延遲執(zhí)行的(Scala中的方法名都很隨意)。

Scala 的 View

再次重申,Scala 的 collection 是一個嚴格 collection,而 view 是非嚴格的。View 是基于一個基礎 collection 的 collection,其中所有的轉換都會延遲執(zhí)行。通過調用 view 函數可以將嚴格 collection 轉換成 view,也可以通過調用 force 方法轉換回來。View 并不緩存結果,每次調用時才會執(zhí)行轉換。就像數據庫的 View,但它是虛擬 collection。

創(chuàng)建一個數據集。

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;
    ...
}

假設有一個寵物集,接下來會利用該集合詳細說明。

過濾器

要求:從集合過濾一只胖乎乎的寵物,胖乎乎的定義是體重超過 50 磅,還想得到一個在 2013年1月1日出生的寵物名單。下面的代碼片段顯示了如何以不同的方式實現(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);
    }
}

這種方式在命令式語言中十分常見。首先,必須創(chuàng)建一個臨時集合,然后遍歷所有元素,存儲滿足條件的元素到臨時集中。的確有點繞口,但其結果和效率都非常不錯。但本人不得不掃興地說,傳統(tǒng)方法比 Streams API 更快。不過,完全不用擔心性能問題,因為代碼的簡潔比輕微的性能增益更重要。

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 過濾集合中的元素。之所以故意兩次調用過濾函數,是想表明 Streams 的 API 設計就像一個 Builder pattern。在 Builder pattern 調用構建方法之前,可以將各種方法串聯(lián)起來。在 Streams API 中,構建方法被稱為終結操作,非終結操作的叫做中間操作。終結操作可能不同于構造函數,因為它在 Streams API 中只能被調用一次。但還有很多可使用的終結操作,比如 collect、count、min、max、iterator、toArray。這些操作會產生結果,而終端操作會消耗值,例如 forEach。那么,你認為傳統(tǒng)方法和 Streams API 哪一個的可讀性更強?

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);

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

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。但首先,必須調用 view 函數把嚴格集轉向非嚴格集,然后再用 tostream 函數把嚴格集轉成一個 stream。

接下來直接上代碼。

分組

通過元素的一個屬性對起所在集合做 group。結果是 Map,其中T是一個泛型類型。

要求:通過類型對寵物分組,諸如狗,貓等等。

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

排序

根據屬性對集合中的元素排序。結果會是任何類型的集合,根據配置來維持元素順序。

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

映射

將給定函數應用在集合元素中。根據定義的函數不同,其返回的結果類型也不同。

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

尋找第一個

返回第一個能與指定 predicate 匹配的值。

要求:找一個名為Handsome的寵物。無論有多少個Handsome,只取第一個。

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

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

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

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

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

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

通過比較 Java 和 Scala 中的一些共同的操作方法 ——filter、group、map 和 find;很明顯 Scala 的方法比 Java 更簡潔。你更喜歡哪一個呢?哪一個的可讀性更強?

在文章的下一個部分,我們將比較哪種方式更快。敬請期待!

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

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

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

轉載請注明本文地址:http://systransis.cn/yun/64767.html

相關文章

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

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

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

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

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

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

    andycall 評論0 收藏0
  • JVM 平臺上的各種語言的開發(fā)指南[z]

    摘要:我們的目標是建立對每一種語言的認識,它們是如何進化的,未來將走向何方。有點的味道是堅持使用動態(tài)類型,但唯一還收到合理擁泵的編程語言,然而一些在企業(yè)的大型團隊中工作的開發(fā)者擇認為這會是的一個缺陷。 為什么我們需要如此多的JVM語言? 在2013年你可以有50中JVM語言的選擇來用于你的下一個項目。盡管你可以說出一大打的名字,你會準備為你的下一個項目選擇一種新的JVM語言么? 如今借助來自...

    phodal 評論0 收藏0
  • 轉 | Java8初體驗(一)lambda表達式語法

    摘要:初體驗下面進入本文的正題表達式。接下來展示表達式和其好基友的配合。吐槽一下方法引用表面上看起來方法引用和構造器引用進一步簡化了表達式的書寫,但是個人覺得這方面沒有的下劃線語法更加通用。 感謝同事【天錦】的投稿。投稿請聯(lián)系 [email protected] 本文主要記錄自己學習Java8的歷程,方便大家一起探討和自己的備忘。因為本人也是剛剛開始學習Java8,所以文中肯定有錯誤和理解偏...

    Lucky_Boy 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<