一文帶你了解Java8?Stream流處理中的收集器技巧
Java 8 引入的 Stream
極大地簡化了集合數(shù)據(jù)的處理,提供了一種現(xiàn)代、函數(shù)式的方式來處理數(shù)據(jù)。然而,在處理流時(shí),我們經(jīng)常需要將流的結(jié)果匯總到集合中或者進(jìn)行各種統(tǒng)計(jì)計(jì)算。這就是收集器(Collectors)發(fā)揮作用的地方。本文將深入探討 Java 8 Stream 中的收集器,介紹收集器的各種用法和技巧,幫助你更好地利用收集器處理數(shù)據(jù)。
什么是收集器(Collectors)
收集器是 Stream
提供的一個(gè)重要功能,用于將流的元素收集到一個(gè)結(jié)果容器中。通過使用收集器,可以讓代碼更加方便的進(jìn)行簡化與重用。其內(nèi)部主要核心是通過 Collectos
完成更加復(fù)雜的計(jì)算轉(zhuǎn)換從而獲取到最終結(jié)果。
Java 8 在 Collectors
類中預(yù)定義了多個(gè)用于收集的方法,使得我們可以輕松地對(duì)流的元素進(jìn)行匯總、分組、分區(qū)以及其他各種操作。
常見的收集器用法
通過 toList 將元素收集到集合中
List<String> names = peopleStream.map(Person::getName) .collect(Collectors.toList());
通過 counting 統(tǒng)計(jì)集合總數(shù)
Long collect = studentList.stream().collect(Collectors.counting());
通過 maxBy 和 minBy 獲取最大值最小值
Optional<Student> optional = studentList.stream().collect(Collectors.maxBy(Comparator.comparing(Student::getAge));) if (optional.isPresent()){ Student student = optional.get(); System.out.println(student); }
通過 summingLnt 進(jìn)行數(shù)據(jù)匯總
Integer collect = peopleStream.collect(Collectors.summingLnt(Person::getAge)); int sum = peopleStream.mapToInt(Person::getAge).sum();
通過 averagingLnt 進(jìn)行平均值獲取
Double collect = peopleStream.collect(Collectors.averagingLnt(Person::getAge));
其內(nèi)部是在收集過程中,對(duì)所有年齡進(jìn)行累加,最后除以平均值
通過 joining 進(jìn)行數(shù)據(jù)拼接
Person collect = peopleStream.collect(Collectors.joining());
這種方式相當(dāng)于將流中每一個(gè)元素的name屬性獲取映射,內(nèi)部通過StringBuilder來把每一個(gè)映射的值進(jìn)行拼接。
通過 groupingBy 將數(shù)據(jù)進(jìn)行分組
Map<Integer,List<Student>> map = peopleStream.collect(Collectors.groupingBy(Person::getAge));
自定義收集器
已經(jīng)通過Collectors中提供的靜態(tài)方法,完成了諸多的收集器操作,雖然它本身提供了諸多方法,但是不一定能夠覆蓋日常開發(fā)中的所有需求,因此,有時(shí)還需要我們根據(jù)自身的業(yè)務(wù)去自定義收集器的實(shí)現(xiàn)。通過實(shí)現(xiàn) Collector
接口,我們可以完全掌控收集的過程。
源碼分析
根據(jù)源碼,Collector 接口需要三個(gè)參數(shù)。
- T: 流中要收集的元素類型
- A: 累加器的類型
- R:收集的結(jié)果類型
如果想要自定義收集器,需要實(shí)現(xiàn) Collector 接口中的五個(gè)方法 Supplier、Accumulator、finisher、combiner、characteristics
supplier:用于創(chuàng)建一個(gè)容器,在調(diào)用它時(shí),需要?jiǎng)?chuàng)建一個(gè)空的累加器實(shí)例,供后續(xù)方法使用。
accumulator:基于supplier中創(chuàng)建的累加容器,進(jìn)行累加操作。
finisher:當(dāng)遍歷完流后,在其內(nèi)部完成最終轉(zhuǎn)換,返回一個(gè)最終結(jié)果。
combiner:用于在并發(fā)情況下,將每個(gè)線程的容器進(jìn)行合并。
characteristics:用于定義收集器行為,如是否可以并行或使用哪些優(yōu)化。其本身是一個(gè)枚舉,內(nèi)部有三個(gè)值,分別為:
- CONCURRENT:表明收集器是并行的且只會(huì)存在一個(gè)中間容器。
- UNORDERED:表明結(jié)果不受流中順序影響,收集是無序的。
- IDENTITY_FINISH:表明累積器的結(jié)果將會(huì)直接作為歸約的最終結(jié)果,跳過finisher()。
實(shí)戰(zhàn)示例:收集合格的學(xué)生
定義自定義收集器
package com.jdk8.features.stream.collector; import com.jdk8.features.lambda.Student; import java.util.ArrayList; import java.util.EnumSet; import java.util.List; import java.util.Set; import java.util.function.BiConsumer; import java.util.function.BinaryOperator; import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collector; public class MyCollector implements Collector<Student, List<Student>,List<Student>> { @Override public Supplier<List<Student>> supplier() { return ArrayList::new; } @Override public BiConsumer<List<Student>, Student> accumulator() { return ((studentList, student) -> { if (student.getIsPass()){ studentList.add(student); } }); } @Override public BinaryOperator<List<Student>> combiner() { return null; } @Override public Function<List<Student>, List<Student>> finisher() { return Function.identity(); } @Override public Set<Characteristics> characteristics() { return EnumSet.of(Characteristics.IDENTITY_FINISH,Characteristics.UNORDERED); } }
使用自定義收集器
import com.jdk8.features.lambda.Student; import java.util.ArrayList; import java.util.List; public class MyCollectorDemo { public static void main(String[] args) { List<Student> studentList = new ArrayList<>(); studentList.add(new Student(1,"張三",18,19)); studentList.add(new Student(2,"李四",19,18)); studentList.add(new Student(3,"王五",20,21)); studentList.add(new Student(4,"趙六",21,80)); List<Student> list = studentList.stream().collect(new MyCollector()); System.out.println(list); } }
結(jié)語
掌握收集器的使用是精通 Java 8 Stream 不可或缺的一部分。在處理流數(shù)據(jù)時(shí),收集器可以幫助我們更輕松地完成數(shù)據(jù)的匯總、分組、分區(qū)等操作。通過本文的介紹,相信你已經(jīng)對(duì)收集器有了更深入的了解,并能夠在實(shí)際項(xiàng)目中靈活運(yùn)用收集器的各種技巧。讓我們在流處理的旅程中更加游刃有余!
到此這篇關(guān)于一文帶你了解Java8 Stream流處理中的收集器技巧的文章就介紹到這了,更多相關(guān)Java8 Stream內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring?Boot中@Autowired注入為空的原因以及解決方法
最近在開發(fā)中遇到了使用@Autowired注解自動(dòng)裝配時(shí)會(huì)報(bào)空指針,發(fā)現(xiàn)對(duì)象并沒有裝配進(jìn)來,下面這篇文章主要給大家介紹了關(guān)于Spring?Boot中@Autowired注入為空的原因以及解決方法,需要的朋友可以參考下2024-01-01Java并發(fā)編程數(shù)據(jù)庫與緩存數(shù)據(jù)一致性方案解析
這篇文章主要為大家介紹了Java并發(fā)編程中數(shù)據(jù)庫與緩存數(shù)據(jù)一致性解決方案,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04java實(shí)現(xiàn)字符串四則運(yùn)算公式解析工具類的方法
今天小編就為大家分享一篇java實(shí)現(xiàn)字符串四則運(yùn)算公式解析工具類的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-07-07SpringBoot集成ShedLock實(shí)現(xiàn)分布式定時(shí)任務(wù)流程詳解
ShedLock是一個(gè)鎖,官方解釋是他永遠(yuǎn)只是一個(gè)鎖,并非是一個(gè)分布式任務(wù)調(diào)度器。一般shedLock被使用的場景是,你有個(gè)任務(wù),你只希望他在單個(gè)節(jié)點(diǎn)執(zhí)行,而不希望他并行執(zhí)行,而且這個(gè)任務(wù)是支持重復(fù)執(zhí)行的2023-02-02SpringBoot啟動(dòng)指定profile的多種方式
這篇文章主要介紹了SpringBoot啟動(dòng)指定profile的多種方式,本文通過圖文實(shí)例相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-09-09