你使用集合作什麼?你不可能簡單地將對象存儲在集合中並將它們留在那裏,在大多數狀況下,使用集合檢索存儲在其中的項。java
再次考慮Lambda表達式小節中描述的場景,假設你正在建立一個社交網絡應用程序,你但願建立一個功能,使管理員可以對知足某些條件的社交網絡應用程序的成員執行任何類型的操做,例如發送消息。git
如前所述,假設這個社交網絡應用程序的成員由如下Person類表示:github
public class Person { public enum Sex { MALE, FEMALE } String name; LocalDate birthday; Sex gender; String emailAddress; // ... public int getAge() { // ... } public String getName() { // ... } }
下面的示例使用for-each循環打印集合roster
中包含的全部成員的名稱:segmentfault
for (Person p : roster) { System.out.println(p.getName()); }
下面的示例打印集合roster
中包含的全部成員,但使用集合操做forEach
:數組
roster .stream() .forEach(e -> System.out.println(e.getName());
儘管在本例中,使用聚合操做的版本比使用for-each循環的版本要長,可是你將看到,對於更復雜的任務,使用批量數據操做的版本將更加簡潔。網絡
在示例BulkDataOperationsExamples中找到本節中描述的代碼摘錄。數據結構
管道是聚合操做的序列,下面的示例打印集合roster
中包含的男性成員,其中包含由聚合操做filter
和forEach
組成的管道:函數
roster .stream() .filter(e -> e.getGender() == Person.Sex.MALE) .forEach(e -> System.out.println(e.getName()));
將此示例與下面的示例進行比較,下面的示例打印集合roster
中包含的男性成員,並使用for-each循環:code
for (Person p : roster) { if (p.getGender() == Person.Sex.MALE) { System.out.println(p.getName()); } }
管道包含如下組件:對象
roster
。filter
)生成一個新的流。stream
從集合roster
建立一個流。filter
操做返回一個新的流,其中包含與其predicate
匹配的元素(此操做的參數),在本例中,predicate
是lambda表達式e -> e.getGender() == Person.Sex.MALE
。若是對象e
的gender
字段的值爲Person.Sex.MALE
,則返回布爾值true
,所以,本例中的filter
操做返回一個包含集合roster
中全部男性成員的流。forEach
)生成非流結果,如原始值(如雙精度值)、集合,或者在forEach
的狀況下,根本沒有值。在本例中,forEach
操做的參數是lambda表達式e -> System.out.println(e.getName())
,調用對象e
上的getName
方法(Java運行時和編譯器推斷對象e
的類型是Person
)。下面的示例計算集合roster
中包含的全部男性成員的平均年齡,其中管道由聚合操做filter
、mapToInt
和average
組成:
double average = roster .stream() .filter(p -> p.getGender() == Person.Sex.MALE) .mapToInt(Person::getAge) .average() .getAsDouble();
mapToInt
操做返回一個類型爲IntStream
的新流(這是一個只包含整數值的流),該操做將其參數中指定的函數應用於特定流中的每一個元素,在這個例子中,函數是Person::getAge
,它是一個方法引用,返回成員的年齡(或者,你可使用lambda表達式e -> e. getage()
)。所以,本例中的mapToInt
操做返回一個流,其中包含集合roster
中全部男性成員的年齡。
average
操做計算類型IntStream
中包含的元素的平均值,它返回一個OptionalDouble
類型的對象,若是流不包含元素,則average
操做返回OptionalDouble
的空實例,調用getAsDouble
方法將拋出NoSuchElementException
。JDK包含許多終端操做,好比average
,經過組合流的內容返回一個值,這些操做稱爲概括操做。
像forEach
這樣的聚合操做看起來像迭代器,然而,它們有幾個根本的區別:
next
這樣的方法來指示它們處理集合的下一個元素,使用內部委託,應用程序決定迭代什麼集合,可是JDK決定如何迭代集合,使用外部迭代,你的應用程序將肯定它迭代哪些集合以及如何迭代。然而,外部迭代只能按順序迭代集合的元素,內部迭代沒有這種限制,它能夠更容易地利用並行計算,這涉及到將一個問題劃分爲子問題,同時解決這些問題,而後將子問題的解的結果組合起來。