當處理集合時,通常會迭代所有元素并對其中的每一個進行處理,這樣的處理使它很難被并行運算。在java8中的StreamAPI可以實現(xiàn)相同功能同時支持并行運算。一個Stream表面上看與一個集合很類似,允許你改變和獲取數(shù)據(jù)。但是實際上它與集合有很大區(qū)別:
- Stream自己不會存儲元素。元素可以被存儲在底層的集合中,或者根據(jù)需要產(chǎn)生出來。
- Stream操作符不會改變源對象。相反,它們會返回一個持有結(jié)果的新Stream。
- Stream操作符可能是延遲執(zhí)行的。這意味著它們會等到需要結(jié)果的時候才執(zhí)行。
Stream遵循“做什么,而不是怎么去做”的原則。使用步驟:
- 創(chuàng)建一個Stream。
- 在一個或多個步驟中,指定將初始Stream轉(zhuǎn)換為另一個Stream的中間操作。
- 使用一個終止操作來產(chǎn)生一個結(jié)果。該操作會強制它之前的延遲操作立即執(zhí)行。在這之后,該Stream就不會再被使用了。
創(chuàng)建Stream
- 通過java8在Collection接口中新添加的stream方法,可以將任何集合轉(zhuǎn)化為一個Stream。
- Stream<String> word = Stream.of("early","more","day");
- 使用Arrays.stream(arrray, from, to)方法將數(shù)組的一部分轉(zhuǎn)化為Stream。
- Stream.empty(); 創(chuàng)建一個不含任何元素的Stream的靜態(tài)方法。
- Stream接口有兩個用來創(chuàng)建無限Stream的靜態(tài)方法。generate方法接受一個無參數(shù)的函數(shù),因此可以創(chuàng)建一個含有常量值的Stream: Stream<String> echos = Stream.generate(() -> "Echo"); 創(chuàng)建一個含有隨機數(shù)字的Stream: Stream<Double> randoms = Stream.generate(Math::random); 創(chuàng)建一個形如0、1、2、3...的無限序列,可以使用iterate方法。它接受一個“種子(seed)”值和一個函數(shù)(從技術(shù)上講,是一個UnaryOperator<T>接口的對象)作為參數(shù),并且會對之前的值重復(fù)應(yīng)用該函數(shù)。如:Stream<BigInteger> integers = Stream.iterate(BigInteger.ZERO, n -> n.add(BigInteger.ONE)); 序列中的第一個元素是種子BigInteger.ZERO; 第二個值是f(seed),或者1(一個大整數(shù)); 下一個元素是f(f(seed)), 或者2;以此類推。
filter、map和flatMap方法
流轉(zhuǎn)換是指從一個流中讀取數(shù)據(jù),并將轉(zhuǎn)換后的數(shù)據(jù)寫入到另一個流中。將一個字符串流轉(zhuǎn)換到另一個只包含長單詞的流:
List<String> wordList = ...;
Stream<String> words = wordList.stream();
Stream<String> longWords = words.filter(w -> w.length() > 12);
我們經(jīng)常需要對一個流中的值進行某種形式的轉(zhuǎn)換。這時可以考慮使用map方法,并傳遞給它一個執(zhí)行轉(zhuǎn)換的函數(shù)。 可以通過:
Stream<String> lowercaseWords = words.map(String::toLoweCase);
將所有單詞轉(zhuǎn)換為小寫形式,這里使用了帶有一個方法引用的map方法。通常,用lambda表達式來代替方法表達式;
Stream<Character> firstChars = words.map(s -> s.charAt(0));
該方法產(chǎn)生的流會包含每個單詞的第一個字符。
使用map方法時,會對每個元素應(yīng)用一個函數(shù),并將返回的值收集到一個新的流中。但當函數(shù)返回值不是一個值而是一個包含多個值的流,此時要將多個流展開成成一個流就需要使用flatMap方法,而不是map方法。
提取子流和組合流
Stream.limit(n)會返回一個包含n個元素的新流(如果原始流的長度小于n,則會返回原始的流)。這個方法特別適用于剪裁指定長度的流。例如:
Stream<Double> randoms = Stream.generate(Math::random).limit(100);
Stream.skip(n)正好相反,它會丟棄前面的n個元素。同時還可以使用Stream類的靜態(tài)方法concat將兩個流連在一起。