摘要:因此,使用并行流需要考慮以下幾點數據量將問題分解之后并行化處理,再將結果合并會帶來額外的開銷。
目錄
簡介
用法
例子
注意點
一. 簡介流是Java8引入的一個新特性,提供了對集合元素一系列便捷的操作,可以用很少的代碼實現復雜的功能。
流有兩大類,分別是對象流(Stream),基本數據流(IntStream、LongStream、DoubleStream)。
流的使用通常為三個步驟:①創建流 ②描述流 ③求值
創建流通過Stream靜態工廠方法來創建,Stream類提供了以下方法創建流。
of:
Stream
IntStream intStream = IntStream.of(new int[]{1, 2, 3});
generator:生成一個無限長度的Stream
可以看作是個工廠,每次返回一個給定類型的對象。
Stream
iterate:生成無限長度的Stream
其元素的生成是重復對給定的種子值(seed)調用用戶指定函數生成的
Stream
empty():生成空流
Stream.empty();
通過文件生成流:File.lines()
Stream
最常用的 通過Collection子類獲取Stream
List
Stream
通過Arrays.stream()封裝數據生成流,也很常用
IntStream intStream = Arrays.stream(new int[]{1, 2, 3});
比較少用的 CharSequence 接口方法 .chars()
String str = "hello world";
IntStream intStream = str.chars();
創建好流之后,就可以描述流了。更準確的說法是,聲明流的中間操作。
中間操作比較常用的有以下幾種(返回值為Stream的均為中間操作)
.filter(man -> man.getAge() > 18) 過濾器
.map(Man::getName) 獲取字段,map操作可以執行多次,將數據轉為我們期望的
.mapToInt 轉為數值流,這個和sum這些組合使用可以省去裝箱成本
.limit(3) 截斷流,前三個
.distinct() 去重
.sorted() 排序
.skip(3) 丟棄前三個
.flatMap(Arrays::stream) 合并流
求值與中間操作相對應的是終端操作,也就是我們的第三步,求值。
常用的終端操作有以下幾種(返回值不為Stream的為終端操作)
.collect(toList()); 結果轉為List格式
.collect(toSet()); 結構轉為Set格式,自帶distinct效果
.count(); 計數
.findfirst(); 找第一個
.findAny(); 找任何一個
.forEach(System.out::println) 為每個元素進行的操作
.min 獲取最小值
.max 獲取最大值
說明流是使用了內部迭代而不是外部迭代三.例子
內部迭代使用了惰性求值,只有在需要結果的那一刻才進行求值。
所有的中間操作(只描述流)都是惰性求值,因為只返回了Stream。
// 用戶類
public class User { private Integer id; private String name; private Integer age; // GET SET Constructor .. }
// 初始化數據
ListuserList = new ArrayList () { /** */ private static final long serialVersionUID = 1L; { add(new User(1, "Luffy", 17)); ? add(new User(2, "Zoro", 19)); add(new User(3, "Nami", 18)); add(new User(4, "Usopp", 17)); add(new User(5, "Sanji", 19)); add(new User(6, "Chopper", 15)); add(new User(7, "Robin", 28)); add(new User(8, "FRANKY", 34)); add(new User(9, "BROOK", 88)); } };
// 例子
@Test public void test1() { // 獲取所有年齡大于17的用戶 List四.注意點users = userList.stream() .filter(user -> user.getAge() > 17) .collect(Collectors.toList()); System.out.println(users); } // 靜態導入Collectors后會更簡潔。 // import static java.util.stream.Collectors.*; @Test public void test2() { // 根據年齡是否大于17歲對集合進行分塊 Map > users = userList.stream() .collect(partitioningBy(u -> u.getAge() > 17)); System.out.println(users); } @Test public void test3() { // 按照年齡,將用戶分組 Map > users = userList.stream() .collect(groupingBy(User::getAge)); System.out.println(users); } @Test public void test4() { // 獲取所有用戶的名稱 List names = userList.stream() .map(User::getName) .collect(toList()); System.out.println(names); } @Test public void test5() { // 獲取年齡最大的用戶(只返回一個) User user = userList.stream() .max((u1, u2) -> { return u1.getAge() > u2.getAge() ? 1 : -1; }) .get(); System.out.println(user); } @Test public void test6() { // 獲取用戶年齡總和 int ageSum = userList.stream() .map(User::getAge) .reduce(0, (acc, element) -> { acc += element; return acc; }); System.out.println(ageSum); ageSum = userList.stream() .map(User::getAge) .reduce(0, Integer::sum); System.out.println(ageSum); ageSum = userList.stream() .collect(summingInt(User::getAge)); System.out.println(ageSum); } @Test public void test7() { // 獲取組成用戶姓名的字母 Set set = userList.stream() .map(User::getName) .map(name -> name.split("")) .flatMap(Arrays::stream) .collect(toSet()); System.out.println(set); }
如何進行調試
// 可以利用peek查看流中的數據狀態 userList.stream() .peek(System.out::println) .map(u -> u.getName()) .peek(System.out::println) .collect(toList());
使用并行還是串行
// 將流改為并行流十分簡單,只需要將stream方法改為parallelStream Map> users = userList.parallelStream() .collect(groupingBy(User::getAge)); // 或是使用 parallel() 聲明為并行 Stream.iterate(0L, i -> i + 1) .parallel() .limit(10) .reduce(0L, Long::sum);
Java8流的并行屬于數據并行,即將數據分為幾部分,利用多核CPU對每塊數據執行運算,最終匯總數據,得到答案。底層是使用了fork/join框架,fork遞歸分解問題,然后每段并行執行,最終join合并結果。?因此,使用并行流需要考慮以下幾點:
數據量 : 將問題分解之后并行化處理,再將結果合并會帶來額外的開銷。
因此數據足夠大,每個數據處理管道花費的時間足夠多時,并行化處理才有意義
將數據對半分解的難易程度 :
ArrayList、數組、IntStream.range,這些數據結構支持隨機讀取,也就是說能輕而易舉地被任意分解。
LinkedList,對半分解太難。需要o(n) 時間復雜度
核的數量 : 單核的機器是沒必要并行化的
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/68998.html
摘要:實戰讀書筆記第一章從方法傳遞到接著上次的,繼續來了解一下,如果繼續簡化代碼。去掉并且生成的數字是萬,所消耗的時間循序流并行流至于為什么有時候并行流效率比循序流還低,這個以后的文章會解釋。 《Java8實戰》-讀書筆記第一章(02) 從方法傳遞到Lambda 接著上次的Predicate,繼續來了解一下,如果繼續簡化代碼。 把方法作為值來傳遞雖然很有用,但是要是有很多類似與isHeavy...
摘要:需要注意的是很多流操作本身就會返回一個流,所以多個操作可以直接連接起來,如下圖這樣,操作可以進行鏈式調用,并且并行流還可以實現數據流并行處理操作。為集合創建并行流。 上一篇文章,小樂給大家介紹了《Java8新特性之方法引用》,下面接下來小樂將會給大家介紹Java8新特性之Stream,稱之為流,本篇文章為上半部分。 1、什么是流? Java Se中對于流的操作有輸入輸出IO流,而Jav...
摘要:前言系列神秘的系列神奇的函數式接口繼上兩篇之后,本文已經系列的第三篇了。相反,他們會返回一個持有結果的新。操作是延遲執行的。截斷流,使其元素不超過給定數量。返回流中元素總數。返回流中最大值。 前言 「Java8系列」神秘的Lambda「Java8系列」神奇的函數式接口繼上兩篇之后,本文已經java8系列的第三篇了。本篇文章比較長,但我希望大家都能認真讀完。讀不完可以先收藏,在找時間讀。...
摘要:表達式體現了函數式編程的思想,即一個函數亦可以作為另一個函數參數和返回值,使用了函數作參數返回值的函數被稱為高階函數。對流對象進行及早求值,返回值不在是一個對象。 Java8主要的改變是為集合框架增加了流的概念,提高了集合的抽象層次。相比于舊有框架直接操作數據的內部處理方式,流+高階函數的外部處理方式對數據封裝更好。同時流的概念使得對并發編程支持更強。 在語法上Java8提供了Lamb...
摘要:一流轉換為數組集合陳楊將流轉換為數組將流轉換為數組將流轉換為集合將流轉換為集合解析 一、流 轉換為數組、集合 package com.java.design.java8.Stream; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context...
摘要:串行與并行可以分為串行與并行兩種,串行流和并行流差別就是單線程和多線程的執行。返回串行流返回并行流和方法返回的都是類型的對象,說明它們在功能的使用上是沒差別的。唯一的差別就是單線程和多線程的執行。 Stream是什么 Stream是Java8中新加入的api,更準確的說: Java 8 中的 Stream 是對集合(Collection)對象功能的增強,它專注于對集合對象進行各種非常便...
閱讀 3793·2021-11-12 10:34
閱讀 2812·2021-09-22 15:14
閱讀 778·2019-08-30 15:53
閱讀 3196·2019-08-30 12:53
閱讀 1280·2019-08-29 18:32
閱讀 2761·2019-08-29 16:41
閱讀 1056·2019-08-26 13:40
閱讀 1795·2019-08-23 18:07