大家可以把Stream當成一個高級版本的Iterator。原始版本的Iterator,用戶只能一個一個的遍歷元素並對其執行某些操作;高級版本的Stream,用戶只要給出需要對其包含的元素執行什么操作,比如“過濾掉長度大於10的字符串”、“獲取每個字符串的首字母”等,具體這些操作如何應用到每個元素上,就給Stream就好了!(這個秘籍,一般人我不告訴他:)。
先看如下幾個例子:
List<Integer> nums = Lists.newArrayList(1,null,3,4,null,6);
nums.stream().filter(num -> num != null).count();
list.stream() .filter(student -> student.getSex().equals("G")) .forEach(student -> System.out.println(student.toString()));
List<String> lastStoneList =
stoneLine.stream()
.filter(s -> s.getWeight() < 500)//挑選出質量小於500g的鵝卵石
.sorted(comparing(Stone::getWeight))//按照質量進行排序
.map(Stone::getName)//提取滿足要求的鵝卵石的名字
.collect(toList());//將名字保存到List中
---------------------
- 創建Stream;
- 轉換Stream,每次轉換原有Stream對象不改變,返回一個新的Stream對象(**可以有多次轉換**);
- 對Stream進行聚合(Reduce)操作,獲取想要的結果;
2.1 使用Stream靜態方法來創建Stream的三種方法:
1. of方法:有兩個overload方法,一個接受變長參數,一個接口單一值
Stream<Integer> integerStream = Stream.of(1, 2, 3, 5);
Stream<String> stringStream = Stream.of("taobao");
2. generator方法:生成一個無限長度的Stream,其元素的生成是通過給定的Supplier(這個接口可以看成一個對象的工廠,每次調用返回一個給定類型的對象)
Stream.generate(() -> Math.random());
Stream.generate(Math::random);
3. iterate方法:也是生成無限長度的Stream,和generator不同的是,其元素的生成是重復對給定的種子值(seed)調用用戶指定函數來生成的。其中包含的元素可以認為是:seed,f(seed),f(f(seed))無限循環。
Stream.iterate(
1
, item -> item +
1
).limit(
10
).forEach(System.out::println);
3. 轉換Stream:
轉換Stream其實就是把一個Stream通過某些行為轉換成一個新的Stream。Stream接口中定義了幾個常用的轉換方法,下面我們挑選幾個常用的轉換方法來解釋。
1. distinct: 對於Stream中包含的元素進行去重操作(去重邏輯依賴元素的equals方法),新生成的Stream中沒有重復的元素;
2. filter: 對於Stream中包含的元素使用給定的過濾函數進行過濾操作,新生成的Stream只包含符合條件的元素;
3. map: 對於Stream中包含的元素使用給定的轉換函數進行轉換操作,新生成的Stream只包含轉換生成的元素。這個方法有三個對於原始類型的變種方法,分別是:mapToInt,mapToLong和mapToDouble。
4. flatMap:和map類似,不同的是其每個元素轉換得到的是Stream對象,會把子Stream中的元素壓縮到父集合中;
5. peek: 生成一個包含原Stream的所有元素的新Stream,同時會提供一個消費函數(Consumer實例),新Stream每個元素被消費的時候都會執行給定的消費函數;
6. limit: 對一個Stream進行截斷操作,獲取其前N個元素,如果原Stream中包含的元素個數小於N,那就獲取其所有的元素;
7. skip: 返回一個丟棄原Stream的前N個元素后剩下元素組成的新Stream,如果原Stream中包含的元素個數小於N,那么返回空Stream;
Stream的類型和創建方式2:
// 從數組創建 int [] source = {1,2,3,4,5,6}; IntStream s = Arrays.stream(source); // 從集合創建 List list = Arrays.asList(1,2,3,4,5); Stream s2 = list.stream(); // 創建1到10的流 IntStream s3 = IntStream.range(1,10); // 直接創建 Stream s4 = Stream.of("wo", "ai", "?")
// 支持串行並行操作的序列,元素只有double,int,Long類型的流 DoubleStream,IntStream,LongStream。
案例:
// 將元素中的所有偶數累加求和
int[] nums = {2, 3, 4, 5, 6}; System.out.println( Arrays.stream(nums) .map(i -> i % 2 == 0 ? i : 0) .reduce(0, Integer::sum) );
// flatMap處理嵌套的list List<List<Integer>> ll = Arrays.asList( Arrays.asList(1, 2, 3), Arrays.asList(11, 22, 33), Arrays.asList(0xF1, 0xF2, 0xF3) ); ll.stream() .flatMap(list -> list.stream()) .map(i -> 2 * i) .forEach(i -> System.out.println(i));
案例三:假設有N條營業數據,前5條是無關的測試數據,中間10條是要參加考核的,參與考核的需要知道其中超過50w(包括50)的數據的交易額平均值,其他不參與考核的忽略
Stream<Integer> trans = Stream.of(11, 9, 2, 13, 1, 2, 99, 54, 23, 66, 70, 23, 46, 50, 100, 10, 24, 18, 19, 2); IntSummaryStatistics all = trans // 前5條跳過,2, 99, 54, 23, 66, 70, 23, 46, 50, 100, 10, 24, 18, 19, 2 .skip(5) // 取10條考核交易 2, 99, 54, 23, 66, 70, 23, 46, 50, 100 .limit(10) // 將50以下的交易剔除 99, 54, 66, 70, 50, 100 .filter(i -> i >= 50) // 轉換成數字。如果是IntStream 則不需要轉換 .mapToInt(i->i) // 將流的統計結果放入包裝對象中 .summaryStatistics(); // 交易總量 439w,平均值為439/6 System.out.println(all.getAverage());
Stream流的特性:
1.不能重復使用。
Stream<Integer> trans = Stream.of(11, 9, 2); trans.forEach(i -> System.out.println(i)); trans.reduce(0, Integer::sum);
當我第二次使用trans時,報錯了。

2.驗證流延遲操作:流只要在終止操作(及早求值)時,才會對數據統一做操作,在沒有遇到求值操作的時候,惰性操作代碼不會被執行。
Stream<Integer> trans = Stream.of(11, 70, 23, 46, 50, 100, 10, 24, 18, 19, 2); trans.map(i->{ System.out.println(i); return i; });

3.不影響源數據。