stream 基礎定義
- 元素序列——就像集合一樣,流也提供了一個接口谣拣,可以訪問特定元素類型的一組有序 值碑韵。因為集合是數據結構,所以它的主要目的是以特定的時間/空間復雜度存儲和訪問元 素(如ArrayList 與 LinkedList)蕊连。但流的目的在于表達計算悬垃,比如你前面見到的 filter、sorted和map甘苍。集合講的是數據尝蠕,流講的是計算。
- 源——流會使用一個提供數據的源载庭,如集合看彼、數組或輸入/輸出資源。
- 數據處理操作——流的數據處理功能支持類似于數據庫的操作昧捷,以及函數式編程語言中 的常用操作闲昭,如filter、map靡挥、reduce序矩、find、match跋破、sort等簸淀。流操作可以順序執(zhí) 行,也可并行執(zhí)行毒返。
此外租幕,流操作有兩個重要的特點。 - 流水線——很多流操作本身會返回一個流拧簸,這樣多個操作就可以鏈接起來劲绪,形成一個大
的流水線。這讓我們下一章中的一些優(yōu)化成為可能盆赤,如延遲和短路贾富。流水線的操作可以看作對數據源進行數據庫式查詢。 - 內部迭代——與使用迭代器顯式迭代的集合不同牺六,流的迭代操作是在背后進行的颤枪。
構建流
所有的流構建方法 最終都會調用如下的這個方法
/*
* @param spliterator a {@code Spliterator} describing the stream elements
* @param parallel if {@code true} then the returned stream is a parallel stream;
* if {@code false} the returned stream is a sequential stream.
*/
public static <T> Stream<T> stream(Spliterator<T> spliterator, boolean parallel) {
Objects.requireNonNull(spliterator);
return new ReferencePipeline.Head<>(spliterator,
StreamOpFlag.fromCharacteristics(spliterator),
parallel);
}
- 由值創(chuàng)建流
Stream 提供兩個靜態(tài)方法可以把值轉換成流
方法一:
List<Integer> list = Arrays.asList(1, 2, 3);
Stream<List<Integer>> stream = Stream.of(list);
方法二:
Stream<Object> stream1 = Stream.of(1, 2, "3");
注:這兩種方法返回類型 是編譯器通過類型推斷得出的。
使用方法二淑际,源碼中有這么一行提示:Creating a stream from an array is safe
- 由數組創(chuàng)建流
List<Integer> list = Arrays.asList(1, 2, 3);
Stream<Integer> stream = list.stream();
- 由函數生成:創(chuàng)建無限流
方法一:迭代
Stream<Integer> stream = Stream.iterate(0, n -> n + 2);
該迭代的源碼如下:
public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f) {
Objects.requireNonNull(f);
final Iterator<T> iterator = new Iterator<T>() {
@SuppressWarnings("unchecked")
T t = (T) Streams.NONE;
@Override
public boolean hasNext() {
return true;
}
@Override
public T next() {
return t = (t == Streams.NONE) ? seed : f.apply(t);
}
};
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
iterator,
Spliterator.ORDERED | Spliterator.IMMUTABLE), false);
}
如上所示畏纲,第二個參數為一個 lambda UnaryOperator<T>
關于這個指令的 解釋是:傳入一個 參數T扇住,返回一個參數T,如 (n -> n+2)盗胀;傳入 一個 (int n)艘蹋,返回一個 (int + 2) 類型相同,
因此票灰,我們有的迭代方式也可以
Stream.iterate(new int[]{0, 1},t -> new int[]{t[1], t[0]+t[1]})
方法二:生成
Stream.generate(Math::random)
迭代生成源碼如下:
public static<T> Stream<T> generate(Supplier<T> s) {
Objects.requireNonNull(s);
return StreamSupport.stream(
new StreamSpliterators.InfiniteSupplyingSpliterator.OfRef<>(Long.MAX_VALUE, s), false);
}
如上所示簿训,此函數只會接受一個 lambda supplier<T> 作為一個生產者,
由于該生產者可能會在類內部存儲某些狀態(tài)米间,但是這些狀態(tài)有可能是可變的,如果在并行流中使用可能不會得到我們的期望值膘侮。
Stream.generate(new Supplier<Object>() {
long sum = 0;
@Override
public Object get() {
return sum += 1;
}
});
這段代碼如果在并行流中使用屈糊,由于sum 會被所有線程共用,所以這種寫法是錯誤的琼了。
迭代 iterate 在迭代的方法中由于每次迭代都是靜態(tài)的 所以下面的這種寫法是正確的:
Stream.iterate(0, new UnaryOperator<Integer>() {
int sum = 1;
@Override
public Integer apply(Integer integer) {
return sum += integer;
}
}).limit(5).parallel().forEach(System.out::println);
但是由于并行流的順序不確定性逻锐,所以我們的期望值:0,1雕薪,2昧诱,4,8 可能和我們運行的結果(某次運行結果:2所袁,8盏档,4,1燥爷,0)并不一致蜈亩。