Java 8 中的 Stream 是對集合(Collection)對象功能的加強,它專一於對集合對象進行各類很是便利、高效的聚合操做(aggregate operation),或者大批量數據操做 (bulk data operation)。 它提供串行和並行兩種模式進行匯聚操做,併發模式可以充分利用多核處理器的優點,使用fork/join並行方式來拆分任務和加速處理過程。數組
###前言安全
Stream 就如同一個迭代器(Iterator),單向,不可往復,數據只能遍歷一次。 流的構成: 獲取一個數據源(source)→ 數據轉換 → 執行操做獲取想要的結果。 每次轉換原有 Stream 對象不改變,返回一個新的 Stream 對象(能夠有屢次轉換)。 轉換操做是lazy(惰性求值,只能迭代一次): 只有在Terminal操做執行時,纔會一次性執行。 Stream 裏有個操做函數的集合,每次轉換操做就是把轉換函數放入這個集合中。 在 Terminal 操做的時候循環 Stream 對應的集合,而後對每一個元素執行全部的函數。
###構造流的幾種常見方法數據結構
1. Individual values Stream stream = Stream.of("a", "b", "c"); 2. Arrays String [] strArray = new String[]{"a", "b", "c"}; stream = Stream.of(strArray); stream = Arrays.stream(strArray); 3. Collections List<String> list = Arrays.asList(strArray); stream = list.stream(); 文件生成流: Stream<String> stream = Files.lines(Paths.get("data.txt"));
###流轉換爲其它數據結構併發
1. Array String[] strArray1 = stream.toArray(String[]::new); 2. Collection List<String> list1 = stream.collect(Collectors.toList()); List<String> list2 = stream.collect(Collectors.toCollection(ArrayList::new)); Set set1 = stream.collect(Collectors.toSet()); Stack stack1 = stream.collect(Collectors.toCollection(Stack::new)); 3. String String str = stream.collect(Collectors.joining()).toString();
###流的操做dom
當把一個數據結構包裝成 Stream 後,就要開始對裏面的元素進行各種操做了。常見的操做能夠歸類以下。 中間操做: Intermediate(主要是打開流,作出某種程度的數據映射/過濾,而後返回一個新的流) map(mapToInt, flatMap)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel、 sequential、 unordered .filter(person -> person.getAge() == 20) 過濾器 .distinct() 去除重複元素,這個方法是經過類的 equals 方法來判斷兩個元素是否相等的 .sorted()(流中的元素的類實現了 Comparable 接口) / sorted((p1, p2) -> p1.getAge() - p2.getAge()) 排序 .sorted(Comparator.comparingInt(Person::getAge)) .limit(long n) 返回前 n 個元素 .skip(long n) 去除前 n 個元素 .map(T -> R) 將流中的每個元素 T 映射爲 R(相似類型轉換) .map(Person::getName) .flatMap(T -> Stream<R>) 將流中的每個元素 T(數組) 映射爲一個流,再把每個流鏈接成爲一個流 .flatMap(Arrays::stream) 結束操做: Terminal(流的最後一個操做) forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator boolean b = list.stream().anyMatch(person -> person.getAge() == 20); 判斷是否有匹配條件的元素 .allMatch(T -> boolean) 是否全部元素都符合匹配條件 .reduce((T, T) -> T) 和 reduce(T, (T, T) -> T) 用於組合流中的元素,如求和,求積,求最大值等 .reduce(0, Integer::sum) reduce 第一個參數 0 表明起始值爲 0 .count() 返回流中元素個數,結果爲 long 類型 .collect() 收集方法 最經常使用的方法,把流中全部元素收集到一個 List Set Collection 中 toList() toSet() toCollection() toMap() joining() 鏈接字符串 counting() 計算總和
###數值流ide
Stream<Integer> 類型,而每一個 Integer 都要拆箱成一個原始類型再進行 sum 方法求和,這樣大大影響了效率。 針對這個問題 Java 8 有良心地引入了數值流 IntStream, DoubleStream, LongStream。 三種對應的包裝類型 Stream: IntStream、LongStream、DoubleStream IntStream.of(new int[]{1, 2, 3}).forEach(System.out::println); IntStream.range(1, 3).forEach(System.out::println); 半開區間[) IntStream.rangeClosed(1, 3).forEach(System.out::println); 閉區間[] 流轉換爲數值流: mapToInt(T -> int) : return IntStream mapToDouble(T -> double) : return DoubleStream mapToLong(T -> long) : return LongStream 數值流轉換爲流: Stream<Integer> stream = intStream.boxed(); 數值流方法: sum() max() min() average()
###並行流(必須是線程安全的)函數
Stream.of(list).parallel();
###無限長度的流線程
generator: generator方法,返回一個無限長度的Stream,其元素由Supplier接口的提供。 在Supplier是一個函數接口,只封裝了一個get()方法,其用來返回任何泛型的值。 - generate(Supplier<T> s):返回一個無限長度的Stream 示例: 1. Stream<Double> generateA = Stream.generate(new Supplier<Double>() { @Override public Double get() { return Math.random(); } }); 2. Stream<Double> generateB = Stream.generate(()->Math.random()); 3. Stream<Double> generateC = Stream.generate(Math::random); iterate iterate方法,其返回的也是一個無限長度的Stream。 與generate方法不一樣的是,其是經過函數f迭代對給指定的元素種子而產生無限連續有序Stream, 其中包含的元素能夠認爲是:seed,f(seed),f(f(seed))無限循環。 - iterate(T seed, UnaryOperator<T> f) 示例: Stream.iterate(1, item -> item + 1).limit(10).forEach(System.out::println); // 打印結果:1,2,3,4,5,6,7,8,9,10 上面示例,種子爲1,也可認爲該Stream的第一個元素, 經過f函數來產生第二個元素。 接着,第二個元素,做爲產生第三個元素的種子,從而產生了第三個元素, 以此類推下去。 須要注意的是,該Stream也是無限長度的, 應該使用filter、limit等來截取Stream,不然會一直循環下去。