JDK 8中的流驱动的集合功能
這篇文章介紹了JDK 8的應(yīng)用–引入了帶有集合的 流 ,以更簡潔地完成通常需要的與集合相關(guān)的功能。 在此過程中,將演示并簡要說明使用Java Streams的幾個關(guān)鍵方面。 請注意,盡管JDK 8 Streams通過并行化支持提供了潛在的性能優(yōu)勢,但這并不是本文的重點。
樣品采集和采集條目
就本文而言, Movie實例將存儲在一個集合中。 以下代碼段適用于這些示例中使用的簡單Movie類。
電影.java
Movie多個實例放置在Java Set中 。 下面顯示了執(zhí)行此操作的代碼,因為它還顯示了在這些實例中設(shè)置的值。 此代碼在類上將“電影”聲明為靜態(tài)字段,然后使用靜態(tài)初始化塊用五個Movie實例填充該字段。
用電影類實例填充電影集
private static final Set<Movie> movies;static {final Set<Movie> tempMovies = new HashSet<>();tempMovies.add(new Movie("Raiders of the Lost Ark", 1981, Genre.ACTION, MpaaRating.PG, 31));tempMovies.add(new Movie("Star Wars: Episode V - The Empire Strikes Back", 1980, Genre.SCIENCE_FICTION, MpaaRating.PG, 12));tempMovies.add(new Movie("Inception", 2010, Genre.SCIENCE_FICTION, MpaaRating.PG13, 13));tempMovies.add(new Movie("Back to the Future", 1985, Genre.SCIENCE_FICTION, MpaaRating.PG, 49));tempMovies.add(new Movie("The Shawshank Redemption", 1994, Genre.DRAMA, MpaaRating.R, 1));movies = Collections.unmodifiableSet(tempMovies); }初探帶有過濾的JDK 8流
通常在集合上執(zhí)行的一種功能是過濾。 下一個代碼清單顯示了如何過濾所有評級為PG的電影的“電影” Set 。 列出之后,我將重點介紹可以從此代碼中得出的一些觀察結(jié)果。
使用PG分級過濾電影
/*** Demonstrate using .filter() on Movies stream to filter by PG ratings* and collect() as a Set.*/ private void demonstrateFilteringByRating() {printHeader("Filter PG Movies");final Set<Movie> pgMovies =movies.stream().filter(movie > movie.getMpaaRating() == MpaaRating.PG).collect(Collectors.toSet());out.println(pgMovies); }第一個示例包括本文中的所有示例也將具有的一件事是在集合上調(diào)用方法stream() 。 此方法返回一個實現(xiàn)java.util.Stream接口的對象。 這些返回的每個Streams均使用針對其調(diào)用stream()方法的集合作為其數(shù)據(jù)源。 此時所有操作都在Stream上,而不是在集合上,后者是Stream的數(shù)據(jù)源。
在上面的代碼清單中,基于“ movies” Set在Stream上調(diào)用filter ( Predicate )方法。 在這種情況下, Predicate由lambda表達(dá)式 movie -> movie.getMpaaRating() == MpaaRating.PG 。 這種相當(dāng)可讀的表示法告訴我們,謂詞是基礎(chǔ)數(shù)據(jù)中具有MPAA等級PG的每部電影。
Stream.filter(Predicate)方法是一個中間操作 ,這意味著它返回Stream的實例,該實例可以由其他操作進(jìn)一步操作。 在這種情況下,還有另一個操作collect(Collector) ,它是由Stream.filter(Predicate)返回的Stream調(diào)用的。 Collectors類具有許多靜態(tài)方法,每個方法都提供一個Collector的實現(xiàn),可以將其提供給此collect(Collector)方法。 在這種情況下,使用Collectors.toSet()獲得一個Collector ,它將指示將流結(jié)果安排在Set 。 Stream.collect(Collector)方法是一個終端操作 ,這意味著它是該行的結(jié)尾,并且不返回Stream實例,因此在執(zhí)行此collection之后無法再執(zhí)行任何Stream操作。
執(zhí)行上述代碼后,它將生成如下輸出:
=========================================================== = Filter PG Movies =========================================================== [Movie: Raiders of the Lost Ark (1981), ACTION, PG, 31, Movie: Back to the Future (1985), SCIENCE_FICTION, PG, 49, Movie: Star Wars: Episode V - The Empire Strikes Back (1980), SCIENCE_FICTION, PG, 12]過濾單個(第一個)結(jié)果
/** * Demonstrate using .filter() on Movies stream to filter by #1 imdb.com* rating and using .findFirst() to get first (presumably only) match.*/ private void demonstrateSingleResultImdbRating() {printHeader("Display One and Only #1 IMDB Movie");final Optional<Movie> topMovie =movies.stream().filter(movie -> movie.getImdbTopRating() == 1).findFirst();out.println(topMovie.isPresent() ? topMovie.get() : "none"); }這個例子與前面的例子有很多相似之處。 像之前的代碼清單一樣,該清單顯示了Stream.filter(Predicate)的Stream.filter(Predicate) ,但是這次謂詞是lambda表達(dá)式movie -> movie.getImdbTopRating() == 1) 。 換句話說,由此過濾器生成的Stream應(yīng)該僅包含具有方法getImdbTopRating()返回數(shù)字1的Movie實例。然后,對Stream.filter(Predicate)返回的Stream執(zhí)行終止操作Stream.findFirst( Stream.filter(Predicate) 。 這將返回流中遇到的第一個條目,并且由于我們的基礎(chǔ)Movie Set實例只有一個IMDb Top 250 Rating為1的實例,因此它將是流中由過濾器生成的第一個也是唯一的條目。
執(zhí)行此代碼清單后,其輸出如下所示:
=========================================================== = Display One and Only #1 IMDB Movie =========================================================== Movie: The Shawshank Redemption (1994), DRAMA, R, 1下一個代碼清單說明了Stream.map(Function)的用法 。
/*** Demonstrate using .map to get only specified attribute from each* element of collection.*/ private void demonstrateMapOnGetTitleFunction() {printHeader("Just the Movie Titles, Please");final List<String> titles = movies.stream().map(Movie::getTitle).collect(Collectors.toList());out.println(titles.size() + " titles (in " + titles.getClass() +"): " + titles); }該Stream.map(Function)方法作用于Stream對調(diào)用它(在我們的例子中, Stream可基于底層Set的Movie對象),并應(yīng)用所提供的功能針對Steam返回一個新的Stream ,從結(jié)果該Function對源Stream 。 在這種情況下, Function由Movie::getTitle表示,這是JDK 8引入的方法reference的示例。 我可以使用lambda表達(dá)式movie -> movie.getTitle()代替方法參考Movie::getTitle來獲得相同的結(jié)果。 方法參考文檔解釋說,這正是方法參考旨在解決的情況:
您使用lambda表達(dá)式創(chuàng)建匿名方法。 但是,有時lambda表達(dá)式除了調(diào)用現(xiàn)有方法外什么也不做。 在這種情況下,通常更容易按名稱引用現(xiàn)有方法。 方法引用使您可以執(zhí)行此操作; 它們是緊湊的,易于閱讀的lambda表達(dá)式,用于已經(jīng)具有名稱的方法。
從上面的代碼中您可能會猜到它, Stream.map(Function)是一個中間操作。 就像前面兩個示例一樣,此代碼清單應(yīng)用了Stream.collect(Collector)的終止操作,但是在這種情況下,是傳遞給它的是Collectors.toList() ,因此結(jié)果數(shù)據(jù)結(jié)構(gòu)是List而不是Set 。
當(dāng)上面的代碼清單運行時,其輸出如下所示:
=========================================================== = Just the Movie Titles, Please =========================================================== 5 titles (in class java.util.ArrayList): [Inception, The Shawshank Redemption, Raiders of the Lost Ark, Back to the Future, Star Wars: Episode V - The Empire Strikes Back]減少(轉(zhuǎn)換為單布爾)操作anyMatch和allMatch
下一個示例不使用在大多數(shù)先前示例中使用的Stream.filter(Predicate) , Stream.map(Function)甚至終止操作Stream.collect(Collector) 。 在此示例中,基于我們的Movie對象Set ,縮減和終止操作Stream.allMatch(Predicate)和Stream.anyMatch(Predicate)直接應(yīng)用于Stream 。
/*** Demonstrate .anyMatch and .allMatch on stream.*/ private void demonstrateAnyMatchAndAllMatchReductions() {printHeader("anyMatch and allMatch");out.println("All movies in IMDB Top 250? " + movies.stream().allMatch(movie -> movie.getImdbTopRating() < 250));out.println("All movies rated PG? " + movies.stream().allMatch(movie -> movie.getMpaaRating() == MpaaRating.PG));out.println("Any movies rated PG? " + movies.stream().anyMatch(movie -> movie.getMpaaRating() == MpaaRating.PG));out.println("Any movies not rated? " + movies.stream().anyMatch(movie -> movie.getMpaaRating() == MpaaRating.NA)); }代碼清單顯示Stream.anyMatch(Predicate)和Stream.allMatch(Predicate)各自返回一個布爾值,分別表示其名稱是否暗示Stream具有至少一個與謂詞匹配的條目還是所有與謂詞匹配的布爾值。 在這種情況下,所有電影都來自imdb.com前250名,因此“ allMatch”將返回true 。 但是,并非所有電影都被評為PG,因此“ allMatch”返回false 。 因為至少有一部電影被評為PG,所以PG評級謂詞的“ anyMatch”返回true ,而N / A評級謂詞的“ anyMatch”返回false因為即使底層Set沒有一部電影也具有MpaaRating.NA評級。 接下來顯示運行此代碼的輸出。
=========================================================== = anyMatch and allMatch =========================================================== All movies in IMDB Top 250? true All movies rated PG? false Any movies rated PG? true Any movies not rated? false輕松確定最小和最大
本文中將Stream的強(qiáng)大功能應(yīng)用于集合操作的最后一個示例演示了Stream.reduce(BinaryOperator)與BinaryOperator的兩個不同實例的結(jié)合使用 : Integer :: min和Integer :: max 。
private void demonstrateMinMaxReductions() {printHeader("Oldest and Youngest via reduce");// Specifying both Predicate for .map and BinaryOperator for .reduce with lambda expressionsfinal Optional<Integer> oldestMovie = movies.stream().map(movie -> movie.getYearReleased()).reduce((a,b) -> Integer.min(a,b));out.println("Oldest movie was released in " + (oldestMovie.isPresent() ? oldestMovie.get() : "Unknown"));// Specifying both Predicate for .map and BinaryOperator for .reduce with method referencesfinal Optional<Integer> youngestMovie = movies.stream().map(Movie::getYearReleased).reduce(Integer::max);out.println("Youngest movie was released in " + (youngestMovie.isPresent() ? youngestMovie.get() : "Unknown")); }這個復(fù)雜的示例說明了如何使用Integer.min(int,int)在基礎(chǔ)Set找到最舊的電影,以及使用Integer.max(int,int)在Set找到最新的電影。 這是通過先用完成Stream.map得到一個新的Stream的Integer由每個發(fā)行年份前提是S Movie在原Stream 。 此Stream的Integer當(dāng)時的具有Stream.reduce(BinaryOperation)與靜態(tài)執(zhí)行的操作Integer用作方法BinaryOperation 。
對于此代碼清單,我在計算最舊的電影( Integer.min(int,int) )時故意在Predicate和BinaryOperation中使用了lambda表達(dá)式,并在計算最新電影時使用了Predicate和BinaryOperation方法引用代替了lambda表達(dá)式( Integer.max(int,int) )。 這證明lambda表達(dá)式或方法引用可以在許多情況下使用。
接下來顯示運行上述代碼的輸出:
=========================================================== = Oldest and Youngest via reduce =========================================================== Oldest movie was released in 1980 Youngest movie was released in 2010結(jié)論
JDK 8 Streams引入了一種強(qiáng)大的機(jī)制來處理Collections。 與直接使用Collections相比,這篇文章側(cè)重于使用Streams帶來的可讀性和簡潔性,但是Streams也具有潛在的性能優(yōu)勢。 這篇文章試圖使用常見的集合處理習(xí)慣用法作為Streams帶給Java的簡潔性的示例。 在此過程中,還討論了與使用JDK流相關(guān)的一些關(guān)鍵概念。 使用JDK 8 Streams最具挑戰(zhàn)性的部分是習(xí)慣了新概念和新語法(例如lambda表達(dá)式和方法引用),但是在玩了幾個示例后很快就學(xué)到了這些內(nèi)容。 一名對概念和語法有很豐富經(jīng)驗的Java開發(fā)人員可以探索Stream API的方法,以獲取比本博文中所示的針對Streams(并因此針對基于Streams的集合)執(zhí)行的操作更長的列表。
其他資源
這篇文章的目的是基于簡單但相當(dāng)普遍的collections操縱示例簡要介紹JDK 8流。 要更深入地了解JDK 8流,以及有關(guān)JDK 8流如何使Collections操作更容易的更多想法,請參見以下文章:
- 使用Java SE 8流處理數(shù)據(jù),第1部分
- 第2部分:使用Java SE 8流處理數(shù)據(jù)
- 本杰明·溫特伯格的Java 8流教程
- David Hartveld 的Stream API簡介
- Java 8 Streams入門
- Java Tutorial的Collections on Streams 聚合操作
- Java Tutorial的Collections 減少流
- Java Tutorial的Collections on Streams 并行性
- Lambda表達(dá)式的語法
- 方法參考
翻譯自: https://www.javacodegeeks.com/2015/01/stream-powered-collections-functionality-in-jdk-8.html
總結(jié)
以上是生活随笔為你收集整理的JDK 8中的流驱动的集合功能的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 速冻手抓饼做法 速冻手抓饼如何做
- 下一篇: 1963鲶鱼计划指什么 1963鲶鱼计划