Java?流處理之收集器詳解
Java 流(Stream)處理操作完成之后,我們可以收集這個(gè)流中的元素,使之匯聚成一個(gè)最終結(jié)果。這個(gè)結(jié)果可以是一個(gè)對(duì)象,也可以是一個(gè)集合,甚至可以是一個(gè)基本類型數(shù)據(jù)。
以記錄 Record 為例:
@Data @NoArgsConstructor @AllArgsConstructor public static class Record { private String col1; private String col2; private int col3; }
記錄 Record 包含三個(gè)屬性:列1(col1)、列2(col2)和 列3(col3)。
創(chuàng)建四個(gè)記錄實(shí)例:
Record r1 = new Record("a", "1", 1); Record r2 = new Record("a", "2", 2); Record r3 = new Record("b", "3", 3); Record r4 = new Record("c", "4", 4);
添加到列表:
List<Record> records = new ArrayList<>(); records.add(r1); records.add(r2); records.add(r3); records.add(r4);
收集所有記錄的 列1 值,以列表形式存儲(chǔ)結(jié)果
List<String> col1List = records.stream() .map(Record::getCol1) .collect(Collectors.toList()); log.info("col1List: {}", Json.toJson(col1List));
輸出結(jié)果:
col1List: ["a","a","b","c"]
收集所有記錄的 列1 值,且去重,以集合形式存儲(chǔ)
Set<String> col1Set = records.stream() .map(Record::getCol1) .collect(Collectors.toSet()); log.info("col1Set: {}", Json.toJson(col1Set));
輸出結(jié)果:
col1Set: ["a","b","c"]
收集記錄的 列2 值和 列3 值的對(duì)應(yīng)關(guān)系,以字典形式存儲(chǔ)
Map<String, Integer> col2Map = records.stream() .collect(Collectors.toMap(Record::getCol2, Record::getCol3)); log.info("col2Map: {}", Json.toJson(col2Map));
輸出結(jié)果:
col2Map: {"1":1,"2":2,"3":3,"4":4}
記錄的 列2 不能有重復(fù)值,否則會(huì)拋出 Duplicate key 異常。
收集所有記錄中 列3 值最大的記錄
Record max = records.stream() .collect(Collectors.maxBy(Comparator.comparing(Record::getCol3))) .orElse(null); log.info("max: {}", Json.toJson(max));
輸出結(jié)果:
max: {"col1":"c","col2":"4","col3":4}
收集所有記錄中 列3 值的總和
int sum = records.stream() .collect(Collectors.summingInt(Record::getCol3)); log.info("sum: {}", sum);
輸出結(jié)果:
sum: 10
流的收集需要通過 Stream.collect() 方法完成,方法的參數(shù)是一個(gè) Collector(收集器) ;收集結(jié)果時(shí),需要根據(jù)收集結(jié)果的目標(biāo)類型,傳遞特定的收集器實(shí)例,如上:
Collectors.toList()
Collectors.toSet()
Collectors.toMap()
Collectors.maxBy()
Collectors.summingInt()
Collectors(java.util.stream.Collectors) 是一個(gè)工具類,內(nèi)置若干收集器,我們可以通過調(diào)用不同的方法快速獲取相應(yīng)的收集器實(shí)例。
收集器(java.util.stream.Collector)本質(zhì)是一個(gè) 接口 ,包含以下五個(gè)方法:
Supplier supplier()
BiConsumer<A, T> accumulator()
BinaryOperator combiner()
Function<A, R> finisher()
Set characteristics()
以 Collectors.toList() 為例演示收集器的工作過程。
創(chuàng)建一個(gè)中間結(jié)果容器
supplier() 方法會(huì)返回一個(gè) Supplier 實(shí)例,調(diào)用該實(shí)例的 get() 方法,會(huì)創(chuàng)建一個(gè)中間結(jié)果容器。
@Override public Supplier<List<String>> supplier() { return new Supplier<List<String>>() { @Override public List<String> get() { List<String> container = new ArrayList<>(); return container; } }; }
考慮到收集的元素類型 String,這里的中間結(jié)果容器類型為 ArrayList 。
根據(jù)收集過程的需要,中間結(jié)果容器可以是任意的數(shù)據(jù)結(jié)構(gòu)。
逐一遍歷流中的每個(gè)元素,處理完成之后,添加到中間結(jié)果
accumulator() 方法會(huì)返回一個(gè) BiConsumer 實(shí)例,它有一個(gè) accept() 方法,
參數(shù)1:中間結(jié)果 參數(shù)2:流中遍歷到的某個(gè)元素
遍歷過程是 Java 自動(dòng)完成的,每遍歷一個(gè)元素,會(huì)自動(dòng)調(diào)用 BiConsumer.accept 方法。我們只需要在方法中實(shí)現(xiàn)元素的處理過程,然后把元素的處理結(jié)果添加到中間結(jié)果中就可以了。
@Override public BiConsumer<List<String>, String> accumulator() { return new BiConsumer<List<String>, String>() { @Override public void accept(List<String> container, String col) { container.add(col); } }; }
這個(gè)示例中,流中的元素不需要任何處理,直接添加至中間結(jié)果即可。
中間結(jié)果轉(zhuǎn)換成最終結(jié)果
finisher() 方法會(huì)返回一個(gè) Fuction 實(shí)例,它有一個(gè) apply() 方法,
參數(shù):中間結(jié)果 返回:最終結(jié)果
遍歷過程結(jié)束之后,Java 會(huì)自動(dòng)調(diào)用 Function.apply() 方法,將中間結(jié)果轉(zhuǎn)換成最終結(jié)果。
@Override public Function<List<String>, List<String>> finisher() { return new Function<List<String>, List<String>>() { @Override public List<String> apply(List<String> container) { return container; } }; }
這個(gè)示例中,中間結(jié)果就是最終結(jié)果,不需要任何處理,直接返回中間結(jié)果即可。
combiner()是做什么的?
流中的元素可以被并行處理,這樣的流稱為并行流。并行流相當(dāng)于把一個(gè)大流切分成多個(gè)小流,內(nèi)部使用多線程,并行處理這些小流。每一個(gè)小流遍歷完成之后,都會(huì)產(chǎn)生一個(gè)小的中間結(jié)果,需要將這些小的中間結(jié)果合并成一個(gè)大的中間結(jié)果。
假設(shè)有兩個(gè)小流,收集開始時(shí),會(huì)創(chuàng)建兩個(gè)中間結(jié)果:
中間結(jié)果也是通過 Supplier.get() 方法創(chuàng)建的。
并行遍歷兩個(gè)小流,將各自流的處理結(jié)果添加到各自的中間結(jié)果中:
combiner() 方法會(huì)返回一個(gè) BinaryOperator 實(shí)例,它有一個(gè) apply() 方法:
參數(shù)1:中間結(jié)果1 參數(shù)2:中間結(jié)果2 返回:中間結(jié)果
Java 會(huì)在合適的時(shí)機(jī)自動(dòng)調(diào)用 BinaryOperator.apply() 方法,將小的中間結(jié)果合并成大的中間結(jié)果。
@Override public BinaryOperator<List<String>> combiner() { return new BinaryOperator<List<String>>() { @Override public List<String> apply(List<String> container1, List<String> container2) { container1.addAll(container2); return container1; } }; }
characteristics()是什么的?
characteristics() 會(huì)返回一個(gè) Characteristics(枚舉)集合實(shí)例,用于設(shè)定收集器的特性,支持以下三個(gè)值:
CONCURRENT
收集器支持并發(fā)使用
UNORDERED
收集器不保證元素順序
IDENTITY_FINISH
收集器中間結(jié)果可直接轉(zhuǎn)換成最終結(jié)果
Java 可以根據(jù)這些特性值,保證收集器正確地、有效率地執(zhí)行。
完整代碼
Collector<String, List<String>, List<String>> collector = new Collector<String, List<String>, List<String>>() { @Override public Supplier<List<String>> supplier() { return new Supplier<List<String>>() { @Override public List<String> get() { List<String> container = new ArrayList<>(); return container; } }; } @Override public BiConsumer<List<String>, String> accumulator() { return new BiConsumer<List<String>, String>() { @Override public void accept(List<String> container, String col) { container.add(col); } }; } @Override public BinaryOperator<List<String>> combiner() { return new BinaryOperator<List<String>>() { @Override public List<String> apply(List<String> container1, List<String> container2) { container1.addAll(container2); return container1; } }; } @Override public Function<List<String>, List<String>> finisher() { return new Function<List<String>, List<String>>() { @Override public List<String> apply(List<String> container) { return container; } }; } @Override public Set<Characteristics> characteristics() { return new HashSet<>(); } }; col1List = records.stream() .map(Record::getCol1) .collect(collector); log.info("col1List: {}", Json.toJson(col1List));
到此這篇關(guān)于Java 流處理之收集器的文章就介紹到這了,更多相關(guān)Java 收集器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解決spring結(jié)合mybatis時(shí)一級(jí)緩存失效的問題
這篇文章主要介紹了解決spring結(jié)合mybatis時(shí)一級(jí)緩存失效的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-11-11JDBC+GUI實(shí)現(xiàn)簡單學(xué)生管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了JDBC+GUI實(shí)現(xiàn)簡單學(xué)生管理系統(tǒng),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-02-02SpringBoot工程啟動(dòng)順序與自定義監(jiān)聽超詳細(xì)講解
這篇文章主要介紹了SpringBoot工程啟動(dòng)順序與自定義監(jiān)聽,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2022-11-11Java并發(fā) CompletableFuture異步編程的實(shí)現(xiàn)
這篇文章主要介紹了Java并發(fā) CompletableFuture異步編程的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01ehcache開源緩存框架_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
Ehcache是現(xiàn)在最流行的純Java開源緩存框架,這篇文章主要介紹了ehcache框架的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07淺析Java虛擬機(jī)詳解之概述、對(duì)象生存法則
這篇文章主要介紹了Java虛擬機(jī)詳解之概述、對(duì)象生存法則,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-04-04Java中樹的存儲(chǔ)結(jié)構(gòu)實(shí)現(xiàn)示例代碼
本篇文章主要介紹了Java中樹的存儲(chǔ)結(jié)構(gòu)實(shí)現(xiàn)示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-09-09