JDK 8中的流驱动的集合功能
這篇文章介紹了JDK 8的應用–引入了帶有集合的 流 ,以更簡潔地完成通常需要的與集合相關的功能。 在此過程中,將演示并簡要說明使用Java Streams的幾個關鍵方面。 請注意,盡管JDK 8 Streams通過并行化支持提供了潛在的性能優勢,但這并不是本文的重點。
樣品采集和采集條目
就本文而言, Movie實例將存儲在一個集合中。 以下代碼段適用于這些示例中使用的簡單Movie類。
電影.java
Movie多個實例放置在Java Set中 。 下面顯示了執行此操作的代碼,因為它還顯示了在這些實例中設置的值。 此代碼在類上將“電影”聲明為靜態字段,然后使用靜態初始化塊用五個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流
通常在集合上執行的一種功能是過濾。 下一個代碼清單顯示了如何過濾所有評級為PG的電影的“電影” Set 。 列出之后,我將重點介紹可以從此代碼中得出的一些觀察結果。
使用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); }第一個示例包括本文中的所有示例也將具有的一件事是在集合上調用方法stream() 。 此方法返回一個實現java.util.Stream接口的對象。 這些返回的每個Streams均使用針對其調用stream()方法的集合作為其數據源。 此時所有操作都在Stream上,而不是在集合上,后者是Stream的數據源。
在上面的代碼清單中,基于“ movies” Set在Stream上調用filter ( Predicate )方法。 在這種情況下, Predicate由lambda表達式 movie -> movie.getMpaaRating() == MpaaRating.PG 。 這種相當可讀的表示法告訴我們,謂詞是基礎數據中具有MPAA等級PG的每部電影。
Stream.filter(Predicate)方法是一個中間操作 ,這意味著它返回Stream的實例,該實例可以由其他操作進一步操作。 在這種情況下,還有另一個操作collect(Collector) ,它是由Stream.filter(Predicate)返回的Stream調用的。 Collectors類具有許多靜態方法,每個方法都提供一個Collector的實現,可以將其提供給此collect(Collector)方法。 在這種情況下,使用Collectors.toSet()獲得一個Collector ,它將指示將流結果安排在Set 。 Stream.collect(Collector)方法是一個終端操作 ,這意味著它是該行的結尾,并且不返回Stream實例,因此在執行此collection之后無法再執行任何Stream操作。
執行上述代碼后,它將生成如下輸出:
=========================================================== = 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]過濾單個(第一個)結果
/** * 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表達式movie -> movie.getImdbTopRating() == 1) 。 換句話說,由此過濾器生成的Stream應該僅包含具有方法getImdbTopRating()返回數字1的Movie實例。然后,對Stream.filter(Predicate)返回的Stream執行終止操作Stream.findFirst( Stream.filter(Predicate) 。 這將返回流中遇到的第一個條目,并且由于我們的基礎Movie Set實例只有一個IMDb Top 250 Rating為1的實例,因此它將是流中由過濾器生成的第一個也是唯一的條目。
執行此代碼清單后,其輸出如下所示:
=========================================================== = 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對調用它(在我們的例子中, Stream可基于底層Set的Movie對象),并應用所提供的功能針對Steam返回一個新的Stream ,從結果該Function對源Stream 。 在這種情況下, Function由Movie::getTitle表示,這是JDK 8引入的方法reference的示例。 我可以使用lambda表達式movie -> movie.getTitle()代替方法參考Movie::getTitle來獲得相同的結果。 方法參考文檔解釋說,這正是方法參考旨在解決的情況:
您使用lambda表達式創建匿名方法。 但是,有時lambda表達式除了調用現有方法外什么也不做。 在這種情況下,通常更容易按名稱引用現有方法。 方法引用使您可以執行此操作; 它們是緊湊的,易于閱讀的lambda表達式,用于已經具有名稱的方法。
從上面的代碼中您可能會猜到它, Stream.map(Function)是一個中間操作。 就像前面兩個示例一樣,此代碼清單應用了Stream.collect(Collector)的終止操作,但是在這種情況下,是傳遞給它的是Collectors.toList() ,因此結果數據結構是List而不是Set 。
當上面的代碼清單運行時,其輸出如下所示:
=========================================================== = 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]減少(轉換為單布爾)操作anyMatch和allMatch
下一個示例不使用在大多數先前示例中使用的Stream.filter(Predicate) , Stream.map(Function)甚至終止操作Stream.collect(Collector) 。 在此示例中,基于我們的Movie對象Set ,縮減和終止操作Stream.allMatch(Predicate)和Stream.anyMatch(Predicate)直接應用于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的強大功能應用于集合操作的最后一個示例演示了Stream.reduce(BinaryOperator)與BinaryOperator的兩個不同實例的結合使用 : 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")); }這個復雜的示例說明了如何使用Integer.min(int,int)在基礎Set找到最舊的電影,以及使用Integer.max(int,int)在Set找到最新的電影。 這是通過先用完成Stream.map得到一個新的Stream的Integer由每個發行年份前提是S Movie在原Stream 。 此Stream的Integer當時的具有Stream.reduce(BinaryOperation)與靜態執行的操作Integer用作方法BinaryOperation 。
對于此代碼清單,我在計算最舊的電影( Integer.min(int,int) )時故意在Predicate和BinaryOperation中使用了lambda表達式,并在計算最新電影時使用了Predicate和BinaryOperation方法引用代替了lambda表達式( Integer.max(int,int) )。 這證明lambda表達式或方法引用可以在許多情況下使用。
接下來顯示運行上述代碼的輸出:
=========================================================== = Oldest and Youngest via reduce =========================================================== Oldest movie was released in 1980 Youngest movie was released in 2010結論
JDK 8 Streams引入了一種強大的機制來處理Collections。 與直接使用Collections相比,這篇文章側重于使用Streams帶來的可讀性和簡潔性,但是Streams也具有潛在的性能優勢。 這篇文章試圖使用常見的集合處理習慣用法作為Streams帶給Java的簡潔性的示例。 在此過程中,還討論了與使用JDK流相關的一些關鍵概念。 使用JDK 8 Streams最具挑戰性的部分是習慣了新概念和新語法(例如lambda表達式和方法引用),但是在玩了幾個示例后很快就學到了這些內容。 一名對概念和語法有很豐富經驗的Java開發人員可以探索Stream API的方法,以獲取比本博文中所示的針對Streams(并因此針對基于Streams的集合)執行的操作更長的列表。
其他資源
這篇文章的目的是基于簡單但相當普遍的collections操縱示例簡要介紹JDK 8流。 要更深入地了解JDK 8流,以及有關JDK 8流如何使Collections操作更容易的更多想法,請參見以下文章:
- 使用Java SE 8流處理數據,第1部分
- 第2部分:使用Java SE 8流處理數據
- 本杰明·溫特伯格的Java 8流教程
- David Hartveld 的Stream API簡介
- Java 8 Streams入門
- Java Tutorial的Collections on Streams 聚合操作
- Java Tutorial的Collections 減少流
- Java Tutorial的Collections on Streams 并行性
- Lambda表達式的語法
- 方法參考
翻譯自: https://www.javacodegeeks.com/2015/01/stream-powered-collections-functionality-in-jdk-8.html
總結
以上是生活随笔為你收集整理的JDK 8中的流驱动的集合功能的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 速冻手抓饼做法 速冻手抓饼如何做
- 下一篇: cjmx:JConsole的命令行版本