Java8流操作囱修,轉載

原文地址: 深藍至尊

一. 流式處理簡介

在我接觸到java8流式處理的時候,我的第一感覺是流式處理讓集合操作變得簡潔了許多召庞,通常我們需要多行代碼才能完成的操作,借助于流式處理可以在一行中實現(xiàn)侧蘸。比如我們希望對一個包含整數(shù)的集合中篩選出所有的偶數(shù)裁眯,并將其封裝成為一個新的List返回,那么在java8之前讳癌,我們需要通過如下代碼實現(xiàn):

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">List<Integer> evens = new ArrayList<>(); for (final Integer num : nums) { if (num % 2 == 0) {
evens.add(num);
}
}</pre>

通過java8的流式處理穿稳,我們可以將代碼簡化為:

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">List<Integer> evens = nums.stream().filter(num -> num % 2 == 0).collect(Collectors.toList());</pre>

先簡單解釋一下上面這行語句的含義,stream()操作將集合轉換成一個流晌坤,filter()執(zhí)行我們自定義的篩選處理逢艘,這里是通過lambda表達式篩選出所有偶數(shù),最后我們通過collect()對結果進行封裝處理骤菠,并通過Collectors.toList()指定其封裝成為一個List集合返回它改。

由上面的例子可以看出,java8的流式處理極大的簡化了對于集合的操作商乎,實際上不光是集合央拖,包括數(shù)組、文件等,只要是可以轉換成流鲜戒,我們都可以借助流式處理专控,類似于我們寫SQL語句一樣對其進行操作。java8通過內(nèi)部迭代來實現(xiàn)對流的處理遏餐,一個流式處理可以分為三個部分:轉換成流伦腐、中間操作、終端操作失都。如下圖:

image

以集合為例柏蘑,一個流式處理的操作我們首先需要調用stream()函數(shù)將其轉換成流,然后再調用相應的中間操作達到我們需要對集合進行的操作粹庞,比如篩選咳焚、轉換等,最后通過終端操作對前面的結果進行封裝信粮,返回我們需要的形式黔攒。

二. 中間操作

我們定義一個簡單的學生實體類,用于后面的例子演示:

[
復制代碼

](javascript:void(0); "復制代碼")

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">public class Student { /** 學號 /
private long id; private String name; private int age; /
* 年級 /
private int grade; /
* 專業(yè) /
private String major; /
* 學校 */
private String school; // 省略getter和setter
}</pre>

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">// 初始化
List<Student> students = new ArrayList<Student>() {
{
add(new Student(20160001, "孔明", 20, 1, "土木工程", "武漢大學"));
add(new Student(20160002, "伯約", 21, 2, "信息安全", "武漢大學"));
add(new Student(20160003, "玄德", 22, 3, "經(jīng)濟管理", "武漢大學"));
add(new Student(20160004, "云長", 21, 2, "信息安全", "武漢大學"));
add(new Student(20161001, "翼德", 21, 2, "機械與自動化", "華中科技大學"));
add(new Student(20161002, "元直", 23, 4, "土木工程", "華中科技大學"));
add(new Student(20161003, "奉孝", 23, 4, "計算機科學", "華中科技大學"));
add(new Student(20162001, "仲謀", 22, 3, "土木工程", "浙江大學"));
add(new Student(20162002, "魯肅", 23, 4, "計算機科學", "浙江大學"));
add(new Student(20163001, "丁奉", 24, 5, "土木工程", "南京大學"));
}
};</pre>

[
復制代碼

](javascript:void(0); "復制代碼")

2.1 過濾

過濾强缘,顧名思義就是按照給定的要求對集合進行篩選滿足條件的元素,java8提供的篩選操作包括:filter不傅、distinct旅掂、limit、skip访娶。

filter
在前面的例子中我們已經(jīng)演示了如何使用filter商虐,其定義為:Stream<T> filter(Predicate<? super T> predicate),filter接受一個謂詞Predicate崖疤,我們可以通過這個謂詞定義篩選條件秘车,在介紹lambda表達式時我們介紹過Predicate是一個函數(shù)式接口,其包含一個test(T t)方法劫哼,該方法返回boolean《E浚現(xiàn)在我們希望從集合students中篩選出所有武漢大學的學生,那么我們可以通過filter來實現(xiàn)权烧,并將篩選操作作為參數(shù)傳遞給filter:

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">List<Student> whuStudents = students.stream()
.filter(student -> "武漢大學".equals(student.getSchool()))

       .collect(Collectors.toList());</pre>

distinct
distinct操作類似于我們在寫SQL語句時眯亦,添加的DISTINCT關鍵字,用于去重處理般码,distinct基于Object.equals(Object)實現(xiàn)妻率,回到最開始的例子,假設我們希望篩選出所有不重復的偶數(shù)板祝,那么可以添加distinct操作:

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">List<Integer> evens = nums.stream()
.filter(num -> num % 2 == 0).distinct()
.collect(Collectors.toList());</pre>

limit
limit操作也類似于SQL語句中的LIMIT關鍵字宫静,不過相對功能較弱,limit返回包含前n個元素的流,當集合大小小于n時孤里,則返回實際長度温技,比如下面的例子返回前兩個專業(yè)為土木工程專業(yè)的學生:

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">List<Student> civilStudents = students.stream()
.filter(student -> "土木工程".equals(student.getMajor())).limit(2)
.collect(Collectors.toList());</pre>

說到limit,不得不提及一下另外一個流操作:sorted扭粱。該操作用于對流中元素進行排序舵鳞,sorted要求待比較的元素必須實現(xiàn)Comparable接口,如果沒有實現(xiàn)也不要緊琢蛤,我們可以將比較器作為參數(shù)傳遞給sorted(Comparator<? super T> comparator)蜓堕,比如我們希望篩選出專業(yè)為土木工程的學生,并按年齡從小到大排序博其,篩選出年齡最小的兩個學生套才,那么可以實現(xiàn)為:

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">List<Student> sortedCivilStudents = students.stream()
.filter(student -> "土木工程".equals(student.getMajor())).sorted((s1, s2) -> s1.getAge() - s2.getAge())
.limit(2)
.collect(Collectors.toList());</pre>

skip
skip操作與limit操作相反,如同其字面意思一樣慕淡,是跳過前n個元素背伴,比如我們希望找出排序在2之后的土木工程專業(yè)的學生,那么可以實現(xiàn)為:

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">List<Student> civilStudents = students.stream()
.filter(student -> "土木工程".equals(student.getMajor()))
.skip(2)
.collect(Collectors.toList());</pre>

通過skip峰髓,就會跳過前面兩個元素傻寂,返回由后面所有元素構造的流,如果n大于滿足條件的集合的長度携兵,則會返回一個空的集合疾掰。

2.2 映射

在SQL中,借助SELECT關鍵字后面添加需要的字段名稱徐紧,可以僅輸出我們需要的字段數(shù)據(jù)静檬,而流式處理的映射操作也是實現(xiàn)這一目的,在java8的流式處理中并级,主要包含兩類映射操作:map和flatMap拂檩。

map
舉例說明,假設我們希望篩選出所有專業(yè)為計算機科學的學生姓名嘲碧,那么我們可以在filter篩選的基礎之上稻励,通過map將學生實體映射成為學生姓名字符串,具體實現(xiàn)如下:

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">List<String> names = students.stream()
.filter(student -> "計算機科學".equals(student.getMajor()))
.map(Student::getName).collect(Collectors.toList());</pre>

除了上面這類基礎的map呀潭,java8還提供了mapToDouble(ToDoubleFunction<? super T> mapper)钉迷,mapToInt(ToIntFunction<? super T> mapper)mapToLong(ToLongFunction<? super T> mapper)钠署,這些映射分別返回對應類型的流糠聪,java8為這些流設定了一些特殊的操作,比如我們希望計算所有專業(yè)為計算機科學學生的年齡之和谐鼎,那么我們可以實現(xiàn)如下:

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">int totalAge = students.stream()
.filter(student -> "計算機科學".equals(student.getMajor()))
.mapToInt(Student::getAge).sum();</pre>

通過將Student按照年齡直接映射為IntStream舰蟆,我們可以直接調用提供的sum()方法來達到目的,此外使用這些數(shù)值流的好處還在于可以避免jvm裝箱操作所帶來的性能消耗。

flatMap
flatMap與map的區(qū)別在于 flatMap是將一個流中的每個值都轉成一個個流身害,然后再將這些流扁平化成為一個流 味悄。舉例說明,假設我們有一個字符串數(shù)組String[] strs = {"java8", "is", "easy", "to", "use"};塌鸯,我們希望輸出構成這一數(shù)組的所有非重復字符侍瑟,那么我們可能首先會想到如下實現(xiàn):

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">List<String[]> distinctStrs = Arrays.stream(strs)
.map(str -> str.split("")) // 映射成為Stream<String[]>
.distinct()
.collect(Collectors.toList());</pre>

在執(zhí)行map操作以后,我們得到是一個包含多個字符串(構成一個字符串的字符數(shù)組)的流丙猬,此時執(zhí)行distinct操作是基于在這些字符串數(shù)組之間的對比涨颜,所以達不到我們希望的目的,此時的輸出為:

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">[j, a, v, a, 8]
[i, s]
[e, a, s, y]
[t, o]
[u, s, e]</pre>

distinct只有對于一個包含多個字符的流進行操作才能達到我們的目的茧球,即對Stream<String>進行操作庭瑰。此時flatMap就可以達到我們的目的:

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">List<String> distinctStrs = Arrays.stream(strs)
.map(str -> str.split("")) // 映射成為Stream<String[]>
.flatMap(Arrays::stream) // 扁平化為Stream<String>
.distinct()
.collect(Collectors.toList());</pre>

flatMap將由map映射得到的Stream<String[]>,轉換成由各個字符串數(shù)組映射成的流Stream<String>抢埋,再將這些小的流扁平化成為一個由所有字符串構成的大流Steam<String>弹灭,從而能夠達到我們的目的。
與map類似揪垄,flatMap也提供了針對特定類型的映射操作:flatMapToDouble(Function<? super T,? extends DoubleStream> mapper)穷吮,flatMapToInt(Function<? super T,? extends IntStream> mapper)flatMapToLong(Function<? super T,? extends LongStream> mapper)福侈。

三. 終端操作

終端操作是流式處理的最后一步酒来,我們可以在終端操作中實現(xiàn)對流查找、歸約等操作肪凛。

3.1 查找

allMatch
allMatch用于檢測是否全部都滿足指定的參數(shù)行為,如果全部滿足則返回true辽社,例如我們希望檢測是否所有的學生都已滿18周歲伟墙,那么可以實現(xiàn)為:

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">boolean isAdult = students.stream().allMatch(student -> student.getAge() >= 18);</pre>

anyMatch
anyMatch則是檢測是否存在一個或多個滿足指定的參數(shù)行為,如果滿足則返回true滴铅,例如我們希望檢測是否有來自武漢大學的學生戳葵,那么可以實現(xiàn)為:

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">boolean hasWhu = students.stream().anyMatch(student -> "武漢大學".equals(student.getSchool()));</pre>

noneMathch
noneMatch用于檢測是否不存在滿足指定行為的元素,如果不存在則返回true汉匙,例如我們希望檢測是否不存在專業(yè)為計算機科學的學生拱烁,可以實現(xiàn)如下:

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">boolean noneCs = students.stream().noneMatch(student -> "計算機科學".equals(student.getMajor()));</pre>

findFirst
findFirst用于返回滿足條件的第一個元素,比如我們希望選出專業(yè)為土木工程的排在第一個學生噩翠,那么可以實現(xiàn)如下:

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">Optional<Student> optStu = students.stream().filter(student -> "土木工程".equals(student.getMajor())).findFirst();</pre>

findFirst不攜帶參數(shù)戏自,具體的查找條件可以通過filter設置,此外我們可以發(fā)現(xiàn)findFirst返回的是一個Optional類型伤锚,關于該類型的具體講解可以參考上一篇:Java8新特性 – Optional類擅笔。

findAny
findAny相對于findFirst的區(qū)別在于,findAny不一定返回第一個,而是返回任意一個猛们,比如我們希望返回任意一個專業(yè)為土木工程的學生念脯,可以實現(xiàn)如下:

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">Optional<Student> optStu = students.stream().filter(student -> "土木工程".equals(student.getMajor())).findAny();</pre>

實際上對于順序流式處理而言,findFirst和findAny返回的結果是一樣的弯淘,至于為什么會這樣設計绿店,是因為在下一篇我們介紹的并行流式處理,當我們啟用并行流式處理的時候庐橙,查找第一個元素往往會有很多限制假勿,如果不是特別需求,在并行流式處理中使用findAny的性能要比findFirst好怕午。

3.2 歸約

前面的例子中我們大部分都是通過collect(Collectors.toList())對數(shù)據(jù)封裝返回废登,如我的目標不是返回一個新的集合,而是希望對經(jīng)過參數(shù)化操作后的集合進行進一步的運算郁惜,那么我們可用對集合實施歸約操作堡距。java8的流式處理提供了reduce方法來達到這一目的。

前面我們通過mapToInt將Stream<Student>映射成為IntStream兆蕉,并通過IntStream的sum方法求得所有學生的年齡之和羽戒,實際上我們通過歸約操作,也可以達到這一目的虎韵,實現(xiàn)如下:

[
復制代碼

](javascript:void(0); "復制代碼")

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">// 前面例子中的方法
int totalAge = students.stream()
.filter(student -> "計算機科學".equals(student.getMajor()))
.mapToInt(Student::getAge).sum(); // 歸約操作
int totalAge = students.stream()
.filter(student -> "計算機科學".equals(student.getMajor()))
.map(Student::getAge)
.reduce(0, (a, b) -> a + b); // 進一步簡化
int totalAge2 = students.stream()
.filter(student -> "計算機科學".equals(student.getMajor()))
.map(Student::getAge)
.reduce(0, Integer::sum); // 采用無初始值的重載版本易稠,需要注意返回Optional
Optional<Integer> totalAge = students.stream()
.filter(student -> "計算機科學".equals(student.getMajor()))
.map(Student::getAge)
.reduce(Integer::sum); // 去掉初始值</pre>

[
復制代碼

](javascript:void(0); "復制代碼")

3.3 收集

前面利用collect(Collectors.toList())是一個簡單的收集操作,是對處理結果的封裝包蓝,對應的還有toSet驶社、toMap,以滿足我們對于結果組織的需求测萎。這些方法均來自于java.util.stream.Collectors亡电,我們可以稱之為收集器。

3.3.1 歸約

收集器也提供了相應的歸約操作硅瞧,但是與reduce在內(nèi)部實現(xiàn)上是有區(qū)別的份乒,收集器更加適用于可變?nèi)萜魃系臍w約操作,這些收集器廣義上均基于Collectors.reducing()實現(xiàn)腕唧。

例1:求學生的總人數(shù)

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">long count = students.stream().collect(Collectors.counting()); // 進一步簡化
long count = students.stream().count();</pre>

例2:求年齡的最大值和最小值

[
復制代碼

](javascript:void(0); "復制代碼")

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">// 求最大年齡
Optional<Student> olderStudent = students.stream().collect(Collectors.maxBy((s1, s2) -> s1.getAge() - s2.getAge())); // 進一步簡化
Optional<Student> olderStudent2 = students.stream().collect(Collectors.maxBy(Comparator.comparing(Student::getAge))); // 求最小年齡
Optional<Student> olderStudent3 = students.stream().collect(Collectors.minBy(Comparator.comparing(Student::getAge)));</pre>

[
復制代碼

](javascript:void(0); "復制代碼")

例3:求年齡總和

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">int totalAge4 = students.stream().collect(Collectors.summingInt(Student::getAge));</pre>

對應的還有summingLong或辖、summingDouble

例4:求年齡的平均值

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">double avgAge = students.stream().collect(Collectors.averagingInt(Student::getAge));</pre>

對應的還有averagingLong枣接、averagingDouble颂暇。

例5:一次性得到元素個數(shù)、總和月腋、均值蟀架、最大值瓣赂、最小值

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">IntSummaryStatistics statistics = students.stream().collect(Collectors.summarizingInt(Student::getAge));</pre>

輸出:

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">IntSummaryStatistics{count=10, sum=220, min=20, average=22.000000, max=24}</pre>

對應的還有summarizingLongsummarizingDouble片拍。

例6:字符串拼接

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">String names = students.stream().map(Student::getName).collect(Collectors.joining()); // 輸出:孔明伯約玄德云長翼德元直奉孝仲謀魯肅丁奉
String names = students.stream().map(Student::getName).collect(Collectors.joining(", ")); // 輸出:孔明, 伯約, 玄德, 云長, 翼德, 元直, 奉孝, 仲謀, 魯肅, 丁奉</pre>

3.3.2 分組

在數(shù)據(jù)庫操作中煌集,我們可以通過GROUP BY關鍵字對查詢到的數(shù)據(jù)進行分組,java8的流式處理也為我們提供了這樣的功能Collectors.groupingBy來操作集合捌省。比如我們可以按學校對上面的學生進行分組:

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">Map<String, List<Student>> groups = students.stream().collect(Collectors.groupingBy(Student::getSchool));</pre>

groupingBy接收一個分類器Function<? super T, ? extends K> classifier苫纤,我們可以自定義分類器來實現(xiàn)需要的分類效果。

上面演示的是一級分組纲缓,我們還可以定義多個分類器實現(xiàn) 多級分組卷拘,比如我們希望在按學校分組的基礎之上再按照專業(yè)進行分組,實現(xiàn)如下:

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">Map<String, Map<String, List<Student>>> groups2 = students.stream().collect(
Collectors.groupingBy(Student::getSchool, // 一級分組祝高,按學校
Collectors.groupingBy(Student::getMajor))); // 二級分組栗弟,按專業(yè)</pre>

實際上在groupingBy的第二個參數(shù)不是只能傳遞groupingBy,還可以傳遞任意Collector類型工闺,比如我們可以傳遞一個Collector.counting乍赫,用以統(tǒng)計每個組的個數(shù):

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">Map<String, Long> groups = students.stream().collect(Collectors.groupingBy(Student::getSchool, Collectors.counting()));</pre>

如果我們不添加第二個參數(shù),則編譯器會默認幫我們添加一個Collectors.toList()陆蟆。

3.3.3 分區(qū)

分區(qū)可以看做是分組的一種特殊情況雷厂,在分區(qū)中key只有兩種情況:true或false,目的是將待分區(qū)集合按照條件一分為二叠殷,java8的流式處理利用ollectors.partitioningBy()方法實現(xiàn)分區(qū)改鲫,該方法接收一個謂詞,例如我們希望將學生分為武大學生和非武大學生林束,那么可以實現(xiàn)如下:

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">Map<Boolean, List<Student>> partition = students.stream().collect(Collectors.partitioningBy(student -> "武漢大學".equals(student.getSchool())));</pre>

分區(qū)相對分組的優(yōu)勢在于像棘,我們可以同時得到兩類結果,在一些應用場景下可以一步得到我們需要的所有結果壶冒,比如將數(shù)組分為奇數(shù)和偶數(shù)讲弄。

以上介紹的所有收集器均實現(xiàn)自接口java.util.stream.Collector,該接口的定義如下:

[
復制代碼

](javascript:void(0); "復制代碼")

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">public interface Collector<T, A, R> { /** * A function that creates and returns a new mutable result container.
*
* @return a function which returns a new, mutable result container / Supplier<A> supplier(); /* * A function that folds a value into a mutable result container.
*
* @return a function which folds a value into a mutable result container / BiConsumer<A, T> accumulator(); /* * A function that accepts two partial results and merges them. The
* combiner function may fold state from one argument into the other and
* return that, or may return a new result container.
*
* @return a function which combines two partial results into a combined
* result / BinaryOperator<A> combiner(); /* * Perform the final transformation from the intermediate accumulation type
* {@code A} to the final result type {@code R}.
*
* <p>If the characteristic {@code IDENTITY_TRANSFORM} is
* set, this function may be presumed to be an identity transform with an
* unchecked cast from {@code A} to {@code R}.
*
* @return a function which transforms the intermediate result to the final
* result / Function<A, R> finisher(); /* * Returns a {@code Set} of {@code Collector.Characteristics} indicating
* the characteristics of this Collector. This set should be immutable.
*
* @return an immutable set of collector characteristics */ Set<Characteristics> characteristics();

}</pre>

[
復制代碼

](javascript:void(0); "復制代碼")

我們也可以實現(xiàn)該接口來定義自己的收集器依痊,此處不再展開。

四. 并行流式數(shù)據(jù)處理

流式處理中的很多都適合采用 分而治之 的思想怎披,從而在處理集合較大時胸嘁,極大的提高代碼的性能,java8的設計者也看到了這一點凉逛,所以提供了 并行流式處理性宏。上面的例子中我們都是調用stream()方法來啟動流式處理,java8還提供了parallelStream()來啟動并行流式處理状飞,parallelStream()本質上基于java7的Fork-Join框架實現(xiàn)毫胜,其默認的線程數(shù)為宿主機的內(nèi)核數(shù)书斜。

啟動并行流式處理雖然簡單,只需要將stream()替換成parallelStream()即可酵使,但既然是并行荐吉,就會涉及到多線程安全問題,所以在啟用之前要先確認并行是否值得(并行的效率不一定高于順序執(zhí)行)口渔,另外就是要保證線程安全样屠。此兩項無法保證,那么并行毫無意義缺脉,畢竟結果比速度更加重要痪欲,以后有時間再來詳細分析一下并行流式數(shù)據(jù)處理的具體實現(xiàn)和最佳實踐。

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末攻礼,一起剝皮案震驚了整個濱河市业踢,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌礁扮,老刑警劉巖知举,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異深员,居然都是意外死亡负蠕,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進店門倦畅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來遮糖,“玉大人,你說我怎么就攤上這事叠赐∮耍” “怎么了?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵芭概,是天一觀的道長赛不。 經(jīng)常有香客問我,道長罢洲,這世上最難降的妖魔是什么踢故? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任惹苗,我火速辦了婚禮殿较,結果婚禮上桩蓉,老公的妹妹穿的比我還像新娘菩颖。我一直安慰自己京景,他們只是感情好缠沈,可當我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布柬赐。 她就那樣靜靜地躺著,像睡著了一般官紫。 火紅的嫁衣襯著肌膚如雪肛宋。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天束世,我揣著相機與錄音悼吱,去河邊找鬼。 笑死良狈,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的笨枯。 我是一名探鬼主播薪丁,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼遇西,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了严嗜?” 一聲冷哼從身側響起粱檀,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎漫玄,沒想到半個月后茄蚯,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡睦优,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年渗常,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片汗盘。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡皱碘,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出隐孽,到底是詐尸還是另有隱情癌椿,我是刑警寧澤,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布菱阵,位于F島的核電站踢俄,受9級特大地震影響,放射性物質發(fā)生泄漏晴及。R本人自食惡果不足惜都办,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望抗俄。 院中可真熱鬧脆丁,春花似錦、人聲如沸动雹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽胰蝠。三九已至歼培,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間茸塞,已是汗流浹背躲庄。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留钾虐,地道東北人噪窘。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像效扫,于是被迫代替她去往敵國和親倔监。 傳聞我的和親對象是個殘疾皇子直砂,可洞房花燭夜當晚...
    茶點故事閱讀 43,612評論 2 350

推薦閱讀更多精彩內(nèi)容