https://blog.csdn.net/xiliunian/article/details/88773718
導(dǎo)航
引例
Collector
什么是Collector
Collector工作原理
特征值
自定義Collector
Collectors詳解
求值
均值:averaging
元素個(gè)數(shù):counting
最值:maxBy嫉晶、minBy
和:summing皂岔、summarizing
分組
groupingBy
groupingByConcurrent
partitioningBy(分區(qū))
其他操作
collectingAndThen
joining
mapping
reducing
toCollection、toList與toSet
toMap與toConcurrentMap
引例
在Java8新特性(二) Stream(流)一文中,由于篇幅有限冷守,有關(guān)聚合操作collect使用到的Collector沒(méi)有展開(kāi)分析格郁,本文將會(huì)詳細(xì)講解Collector以及Collectors缠劝。
老規(guī)矩先來(lái)看一個(gè)例子妖泄。到了收獲的季節(jié),農(nóng)場(chǎng)主需要把果園里的蘋(píng)果根據(jù)顏色分類(lèi)客税,然后送往銷(xiāo)售商那邊冀膝。只是將蘋(píng)果分類(lèi)是難不倒我們的,下面用代碼實(shí)現(xiàn)農(nóng)場(chǎng)主的需求:
public class Apple{
private String color;
private Integer weight;
public Apple(String color, Integer weight) {
this.color = color;
this.weight = weight;
}
public String getColor() {
return color;
}
public Integer getWeight() {
return weight;
}
@Override
public String toString() {
return "Apple [color=" + color + ", weight=" + weight + "]";
}
}
public class TestCollectByNormal {
public static List<Apple> orchard = Arrays.asList(new Apple("green", 150),
new Apple("red", 170), new Apple("green", 100), new Apple("red", 170),
new Apple("yellow", 170), new Apple("green", 150));
public static void main(String[] args) {
Map<String, List<Apple>> baskets = new HashMap<>();
for (Apple apple : orchard) {
String color = apple.getColor();
List<Apple> basket = baskets.get(color);
if (null == basket) {
basket = new ArrayList<>();
baskets.put(color, basket);
}
basket.add(apple);
}
System.out.println(baskets);
}
}
既然我們?cè)趯W(xué)習(xí)Java8新特性霎挟,不妨用學(xué)到的東西來(lái)重寫(xiě)上面的例子:
public class TestCollectByOptional {
public static void main(String[] args) {
Map<String, List<Apple>> baskets = new HashMap<>();
TestCollectByNormal.orchard.forEach(apple -> {
List<Apple> basket = Optional.ofNullable(baskets.get(apple.getColor()))
.orElseGet(() -> {
List<Apple> tempbasket = new ArrayList<>();
baskets.put(apple.getColor(), tempbasket);
return tempbasket;
});
basket.add(apple);
});
System.out.println(baskets);
}
}
比較上面的兩種做法窝剖,二者的代碼量都不少,也不夠簡(jiǎn)潔酥夭。下面使用Collector來(lái)改進(jìn):
public class TestCollectByCollector {
public static void main(String[] args) {
Map<String, List<Apple>> baskets = TestCollectByNormal.orchard.stream()
.collect(Collectors.groupingBy(Apple::getColor));
System.out.println(baskets);
}
}
借助于Collector赐纱,我們只用一行代碼就完成了上面兩種方法中的所有操作。這就是Collector的強(qiáng)大之處熬北。
Collector
什么是Collector
JavaDoc中對(duì)Collector的描述如下:
A mutable reduction operation that accumulates input elements into a mutable result container, optionally transforming the accumulated result into a final representation after all input elements have been processed. Reduction operations can be performed either sequentially or in parallel.
Collector是一種可變的匯聚操作疙描,它將輸入元素累積到一個(gè)可變的結(jié)果容器中。在所有的元素處理完成后讶隐,Collector將累積的結(jié)果轉(zhuǎn)換成一個(gè)最終的表示(這是一個(gè)可選的操作)起胰。Collector支持串行和并行兩種方式執(zhí)行。
Collector接口中聲明五個(gè)方法和一個(gè)枚舉常量:
public interface Collector<T, A, R> {
Supplier<A> supplier();
BiConsumer<A, T> accumulator();
BinaryOperator<A> combiner();
Function<A, R> finisher();
Set<Characteristics> characteristics();
enum Characteristics {
CONCURRENT,
UNORDERED,
IDENTITY_FINISH
}
....
}
Collector接口有三個(gè)泛型巫延,它們的含義如下:
T:輸入的元素類(lèi)型
A:累積結(jié)果的容器類(lèi)型
R:最終生成的結(jié)果類(lèi)型
Collector工作原理
Collector通過(guò)下面四個(gè)方法協(xié)同工作以完成匯聚操作:
supplier: 創(chuàng)建新的結(jié)果容器
accumulator:將輸入元素合并到結(jié)果容器中
combiner:合并兩個(gè)結(jié)果容器(并行流使用效五,將多個(gè)線程產(chǎn)生的結(jié)果容器合并)
finisher:將結(jié)果容器轉(zhuǎn)換成最終的表示
下面是串行流情況下Collector的工作邏輯:
首先supplier會(huì)提供結(jié)果容器地消,然后accumulator向結(jié)果容器中累積元素,最后finisher將結(jié)果容器轉(zhuǎn)換成最終的返回結(jié)果畏妖。如果結(jié)果容器類(lèi)型和最終返回結(jié)果類(lèi)型一致脉执,那么finisher就可以不執(zhí)行,這就是之前說(shuō)這是一個(gè)可選的操作的原因戒劫。
而combiner是和并行流相關(guān)的半夷,在串行流中combiner并不起作用。JavaDoc中介紹如下:
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.
combiner方法接受兩個(gè)部分的結(jié)果并合并他們迅细,該方法可能會(huì)把一個(gè)結(jié)果容器折疊到另一個(gè)結(jié)果容器中并返回巫橄,也可能返回一個(gè)新的結(jié)果容器。
假如在并行流中對(duì)元素的操作分別在三條線程中完成茵典,三條線程會(huì)返回三個(gè)結(jié)果容器湘换。此時(shí)combiner就可能會(huì)這樣處理多個(gè)線程中的結(jié)果容器:先將線程2的結(jié)果容器2中元素合并到線程1的結(jié)果容器1中,并返回結(jié)果容器1敬尺;再把線程3的結(jié)果容器3中的元素合并到線程1的結(jié)果容器1中;最后返回結(jié)果容器1贴浙。
特征值
除上述四個(gè)方法Collector中還有一個(gè)characteristics()方法砂吞,該方法用于給Collector實(shí)現(xiàn)類(lèi)設(shè)置特征值。枚舉常量Characteristics 中共有三個(gè)特征值崎溃,它們的具體含義如下:
CONCURRENT:表示結(jié)果容器只有一個(gè)(即使是在并行流的情況下)蜻直。只有在并行流且收集器不具備此特性的情況下,combiner()返回的lambda表達(dá)式才會(huì)執(zhí)行(中間結(jié)果容器只有一個(gè)就無(wú)需合并)袁串。設(shè)置此特性時(shí)意味著多個(gè)線程可以對(duì)同一個(gè)結(jié)果容器調(diào)用概而,因此結(jié)果容器必須是線程安全的。
UNORDERED:表示流中的元素?zé)o序囱修。
IDENTITY_FINISH:表示中間結(jié)果容器類(lèi)型與最終結(jié)果類(lèi)型一致赎瑰。設(shè)置此特性時(shí)finiser()方法不會(huì)被調(diào)用。
自定義Collector
明白Collector的原理之后破镰,我們就可以自定義Collector實(shí)現(xiàn)餐曼。下面我們完成一個(gè)Collector實(shí)現(xiàn)——將輸入元素收集到Set集合中。
明確需求之后鲜漩,我們就可以確定下來(lái)Collector實(shí)現(xiàn)的三個(gè)泛型具體是什么:
T(輸入的元素類(lèi)型):T
A(累積結(jié)果的容器類(lèi)型):Set<T>
R(最終生成的結(jié)果類(lèi)型):Set<T>
完成的Collector實(shí)現(xiàn)如下:
public class MySetCollector<T> implements Collector<T, Set<T>, Set<T>> {
@Override
public Supplier<Set<T>> supplier() {
System.out.println("supplier invoked");
return HashSet::new;
}
@Override
public BiConsumer<Set<T>, T> accumulator() {
System.out.println("accumulator invoked");
// return HashSet<T>::add; // 報(bào)錯(cuò)
/**
* 作為accumulator而言源譬,它能明確的僅僅是supplier提供的結(jié)果容器類(lèi)型是Set類(lèi)型,
* 而不知道supplier提供的具體結(jié)果容器類(lèi)型(這里是HashSet)孕似。
* 如果supplier提供的結(jié)果容器類(lèi)型是TreeSet類(lèi)型踩娘,
* 那么accumulator使用HashSet提供的add方法就會(huì)出錯(cuò)。
* 因此這里應(yīng)該使用Set提供的add方法喉祭。
*/
return Set<T>::add;
}
@Override
public BinaryOperator<Set<T>> combiner() {
System.out.println("combiner invoked");
return (set1, set2) -> {
set1.addAll(set2);
return set1;
};
}
@Override
public Function<Set<T>, Set<T>> finisher() {
System.out.println("finisher invoked");
return Function.identity(); // return t -> t;
}
@Override
public Set<Characteristics> characteristics() {
System.out.println("characteristics invoked");
// 結(jié)果容器類(lèi)型和最終結(jié)果類(lèi)型一致养渴,設(shè)置IDENTITY_FINISH特性
return Collections.unmodifiableSet(EnumSet
.of(Collector.Characteristics.IDENTITY_FINISH));
}
}
測(cè)試我們自定義的Collector實(shí)現(xiàn)是否發(fā)揮了作用:
public class TestMyCollector {
public static void main(String[] args) {
List<String> data = Arrays.asList("hello", "world", "hello");
Set<String> result = data.stream().collect(new MySetCollector<>());
System.out.println(result);
}
}
打印結(jié)果如下:
supplier invoked
accumulator invoked
combiner invoked
characteristics invoked
characteristics invoked
[world, hello]
打印結(jié)果是符合我們的預(yù)期的雷绢,但是從打印結(jié)果中,我們可以發(fā)現(xiàn)兩個(gè)問(wèn)題:
1厚脉、“finisher invoked”并沒(méi)有打印习寸,說(shuō)明finisher()方法沒(méi)有被調(diào)用。
查看collect()方法實(shí)現(xiàn)(位于ReferencePipeline類(lèi))傻工,我們來(lái)看該方法是如何調(diào)用Collector的:
public final <R, A> R collect(Collector<? super P_OUT, A, R> collector) {
A container;
if (isParallel() // 這一段是并行流邏輯霞溪,可以跳過(guò)不看
&& (collector.characteristics().contains(Collector.Characteristics.CONCURRENT))
&& (!isOrdered() || collector.characteristics().contains(Collector.Characteristics.UNORDERED))) {
container = collector.supplier().get();
BiConsumer<A, ? super P_OUT> accumulator = collector.accumulator();
forEach(u -> accumulator.accept(container, u));
}
else {
container = evaluate(ReduceOps.makeRef(collector));
}
return collector.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)
? (R) container
: collector.finisher().apply(container);
}
我們?cè)谧远x的Collector實(shí)現(xiàn)——MySetCollector中設(shè)置了IDENTITY_FINISH特性,通過(guò)上面的源碼可以知道:如果Collector實(shí)現(xiàn)中沒(méi)有IDENTITY_FINISH特性中捆,才會(huì)調(diào)用實(shí)現(xiàn)類(lèi)中的finisher()方法鸯匹,否則直接將中間結(jié)果容器強(qiáng)轉(zhuǎn)成最終的結(jié)果類(lèi)型。
因此只有在百分百確定中間結(jié)果類(lèi)型和最終的結(jié)果類(lèi)型一致時(shí)泄伪,才可以為實(shí)現(xiàn)類(lèi)設(shè)置IDENTITY_FINISH特性殴蓬,否則很可能會(huì)出現(xiàn)類(lèi)型轉(zhuǎn)換異常。
2蟋滴、"combiner invoked"打印了染厅,然而我們的程序中使用的是串行流。
繼續(xù)跟進(jìn)到makeRef()方法中:
public static <T, I> TerminalOp<T, I> // makeRef部分源碼
makeRef(Collector<? super T, I, ?> collector) {
Supplier<I> supplier = Objects.requireNonNull(collector).supplier();
BiConsumer<I, ? super T> accumulator = collector.accumulator();
BinaryOperator<I> combiner = collector.combiner();
....
}
從上面的源碼中可以看到津函,makeRef()方法中用一個(gè)變量記錄調(diào)用combiner()方法返回的Lambda表達(dá)式肖粮,所以"combiner invoked"會(huì)被打印,而該Lambda表達(dá)式并沒(méi)有被調(diào)用(可以在此Lambda表達(dá)式中加入打印語(yǔ)句驗(yàn)證)尔苦。
Collectors詳解
Collectors是一個(gè)工具類(lèi)涩馆,提供常用的Collector實(shí)現(xiàn)。Collectors中定義有實(shí)現(xiàn)Collector接口的內(nèi)部類(lèi)CollectorImpl,Collectors提供方法的返回值都是CollectorImpl對(duì)象。
public final class Collectors {
static class CollectorImpl<T, A, R> implements Collector<T, A, R> {...}
...
}
求值
均值:averaging
averaging操作可以計(jì)算輸入元素的均值诡右,該操作包括三個(gè)方法:
<T> Collector<T, ?, Double> averagingInt(ToIntFunction<? super T> mapper)
<T> Collector<T, ?, Double> averagingLong(ToLongFunction<? super T> mapper)
<T> Collector<T, ?, Double> averagingDouble(ToDoubleFunction<? super T> mapper)
public class TestCollectors1 {
public static List<Apple> data = Arrays.asList(new Apple("green", 210),
new Apple("red", 170), new Apple("green", 100), new Apple("red", 170),
new Apple("yellow", 170), new Apple("green", 150));
public static void main(String[] args) {
Double result = data.stream()
.collect(Collectors.averagingInt(Apple::getWeight));
System.out.println(result);
}
}
打印結(jié)果如下:
161.66666666666666
元素個(gè)數(shù):counting
counting()方法可以統(tǒng)計(jì)輸入元素的個(gè)數(shù)。
<T> Collector<T, ?, Long> counting()
public class TestCollectors2 {
public static void main(String[] args) {
Long result = TestCollectors1.data.stream().collect(Collectors.counting());
System.out.println(result);
Long emptyStreamResult = Stream.empty().collect(Collectors.counting());
System.out.println(emptyStreamResult); // 空的流中沒(méi)有元素,返回0
}
}
打印結(jié)果如下:
6
0
值得思考的是涯雅,Stream也提供有相同功能的count()方法:
long count = TestCollectors1.appleList.stream().count(); // 該方法返回流中元素個(gè)數(shù)
為什么在兩個(gè)地方提供擁有相同功能的方法呢?雖然這兩種操作都可以達(dá)到相同的目的展运,但是這兩個(gè)方法的返回值類(lèi)型是不同的——count()方法的返回值是long型斩芭,counting()方法返回值是Collector類(lèi)型。在后面談到分組操作時(shí)乐疆,我們可以看到counting()方法的返回值又可以作為其他方法的參數(shù)划乖,實(shí)現(xiàn)更高效的操作。
所以對(duì)于同一個(gè)目的挤土,可能有多個(gè)方法可以實(shí)現(xiàn)琴庵,我們需要根據(jù)情況選擇最優(yōu)的那個(gè)。
最值:maxBy、minBy
maxBy和minBy操作可以找出輸入元素中的最大最小值迷殿。
<T> Collector<T, ?, Optional<T>> minBy(Comparator<? super T> comparator)
<T> Collector<T, ?, Optional<T>> maxBy(Comparator<? super T> comparator)
public class TestCollectors3 {
public static void main(String[] args) {
TestCollectors1.data.stream()
.collect(Collectors.maxBy(Comparator.comparingInt(Apple::getWeight)))
.ifPresent(System.out::println);
}
}
打印結(jié)果如下:
Apple [color=green, weight=210]
和:summing儿礼、summarizing
summing操作可以計(jì)算輸入元素的總和,該操作包含三個(gè)方法:
<T> Collector<T, ?, Integer> summingInt(ToIntFunction<? super T> mapper)
<T> Collector<T, ?, Long> summingLong(ToLongFunction<? super T> mapper)
<T> Collector<T, ?, Double> summingDouble(ToDoubleFunction<? super T> mapper)
相較于summing操作只能計(jì)算和庆寺,summarizing操作則可以提供更強(qiáng)大的計(jì)算:該操作可以統(tǒng)計(jì)輸入元素個(gè)數(shù)蚊夫、和以及最值。summarizing操作也提供三個(gè)方法:
<T> Collector<T, ?, IntSummaryStatistics> summarizingInt(ToIntFunction<? super T> mapper)
<T> Collector<T, ?, LongSummaryStatistics> summarizingLong(ToLongFunction<? super T> mapper)
<T> Collector<T, ?, DoubleSummaryStatistics> summarizingDouble(ToDoubleFunction<? super T> mapper)
public class TestCollectors4 {
public static void main(String[] args) {
testSummingInt();
testSummarizingInt();
}
private static void testSummingInt() {
Integer result = TestCollectors1.data.stream()
.collect(Collectors.summingInt(Apple::getWeight));
System.out.println(result);
}
private static void testSummarizingInt() {
System.out.println("===================");
IntSummaryStatistics result = TestCollectors1.data.stream()
.collect(Collectors.summarizingInt(Apple::getWeight));
System.out.println(result);
}
}
打印結(jié)果如下:
970
IntSummaryStatistics{count=6, sum=970, min=100, average=161.666667, max=210}
分組
groupingBy
groupingBy操作可以將輸入元素進(jìn)行分組懦尝。Collectors提供三個(gè)重載的groupingBy()方法:
groupingBy(Function<? super T, ? extends K> classifier):classifier提供結(jié)果Map(HashMap)的鍵
groupingBy(Function<? super T, ? extends K> classifier, Collector<? super T, A, D> downstream):downstream提供結(jié)果Map和值
groupingBy(Function<? super T, ? extends K> classifier, Supplier<M> mapFactory, Collector<? super T, A, D> downstream): mapFactory指定結(jié)果Map的類(lèi)型
前面介紹counting()方法的時(shí)候說(shuō)過(guò) :counting()方法的返回值又可以作為其他方法的參數(shù)知纷。擁有兩個(gè)及以上參數(shù)的groupingBy()方法,可以接收一個(gè)Collector類(lèi)型參數(shù)作為Map的值陵霉。這時(shí)counting()方法就可以派上用場(chǎng):
public class TestCollectors5 {
public static void main(String[] args) {
TreeMap<String, Long> result = TestCollectors1.data.stream()
.collect(Collectors.groupingBy(Apple::getColor,
TreeMap::new, Collectors.counting()));
System.out.println(result);
}
}
打印結(jié)果如下:
{green=3, red=2, yellow=1}
groupingByConcurrent
具體操作同groupingBy()琅轧,將元素整理成ConcurrentMap。
public class TestCollectors6 {
public static void main(String[] args) {
ConcurrentSkipListMap<String, Double> result = TestCollectors1.data
.stream().collect(Collectors.groupingByConcurrent(Apple::getColor,
ConcurrentSkipListMap::new, Collectors.averagingInt(Apple::getWeight)));
System.out.println(result);
}
}
打印結(jié)果如下:
{green=153.33333333333334, red=170.0, yellow=170.0}
partitioningBy(分區(qū))
分區(qū)是分組的一種特殊情況踊挠,該操作將輸入元素分為兩類(lèi)(即鍵是true和false的Map)乍桂。Collectors提供兩個(gè)重載的partitioningBy()方法:
partitioningBy(Predicate<? super T> predicate):predicate提供分區(qū)依據(jù)
partitioningBy(Predicate<? super T> predicate,Collector<? super T, A, D> downstream):downstream提供結(jié)果Map的值
public class TestCollectors7 {
public static void main(String[] args) {
Map<Boolean, Double> collect = TestCollectors1.data.stream()
.collect(Collectors.partitioningBy(
apple -> "green".equals(apple.getColor()),
Collectors.averagingInt(Apple::getWeight)));
System.out.println(collect);
}
}
打印結(jié)果如下:
{false=170.0, true=153.33333333333334}
其他操作
collectingAndThen
collectingAndThen()方法接收兩個(gè)參數(shù):downstream(Collector類(lèi)型)和finisher(Function類(lèi)型),在調(diào)用downstream之后效床,將調(diào)用結(jié)果值作為finisher的傳入值睹酌,再調(diào)用finisher。
collectingAndThen(Collector<T,A,R> downstream, Function<R,RR> finisher)
public class TestCollectors8 {
public static void main(String[] args) {
Optional.ofNullable(TestCollectors1.data.stream().collect(Collectors
.collectingAndThen(Collectors.averagingInt(Apple::getWeight),
item -> "average weight is " + item)))
.ifPresent(System.out::println);
}
}
打印結(jié)果如下:
average weight is 161.66666666666666
joining
joining操作可以將輸入元素(字符串類(lèi)型)拼接成字符串剩檀。Collectors提三個(gè)重載的joining()方法:
joining():拼接輸入元素
joining(CharSequence delimiter):將delimiter作為分隔符
joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix):將prefix作為前綴憋沿,suffix作為后綴
public class TestCollectors9 {
public static void main(String[] args) {
String result = TestCollectors1.data.stream()
.map(Apple::getColor).collect(Collectors.joining(",", "Color[", "]"));
System.out.println(result);
}
}
打印結(jié)果如下:
Color[green,red,green,red,yellow,green]
mapping
mapping()方法接收兩個(gè)參數(shù):mapper(Function類(lèi)型)和downstream(Collector類(lèi)型),在調(diào)用mapper之后谨朝,將調(diào)用結(jié)果的返回值作為downstream的輸入元素卤妒,再調(diào)用downstream甥绿。
不難發(fā)現(xiàn)此方法調(diào)用參數(shù)的順序和collectingAndThen()方法相反字币。
mapping(Function<? super T, ? extends U> mapper,Collector<? super U, A, R> downstream)
public class TestCollectors10 {
public static void main(String[] args) {
String result = TestCollectors1.data.stream()
.collect(Collectors.mapping(Apple::getColor, Collectors.joining()));
System.out.println(result);
}
}
打印結(jié)果如下:
greenredgreenredyellowgreen
reducing
reducing操作可以對(duì)輸入元素執(zhí)行匯聚操作。Collectors提供三個(gè)重載的reducing()方法:
reducing(BinaryOperator<T> op):對(duì)輸入的元素應(yīng)用op操作
reducing(T identity, BinaryOperator<T> op):提供初始值identity
reducing(U identity, Function<? super T, ? extends U> mapper, BinaryOperator<U> op):在對(duì)元素進(jìn)行op操作之前共缕,先進(jìn)行mapper操作
public class TestCollectors11 {
public static void main(String[] args) {
testReducingByOperator();
testReducingByIdentityAnaOperator();
testReducingByIdentityAnaOperatorAndFunction();
}
private static void testReducingByOperator() {
TestCollectors1.data.stream().collect(Collectors
.reducing(BinaryOperator.maxBy(Comparator.comparingInt(Apple::getWeight))))
.ifPresent(System.out::println);
}
public static void testReducingByIdentityAnaOperator() {
System.out.println("===================");
Integer collect = TestCollectors1.data.stream().map(Apple::getWeight)
.collect(Collectors.reducing(0, Integer::sum));
System.out.println(collect);
}
private static void testReducingByIdentityAnaOperatorAndFunction() {
System.out.println("===================");
Integer collect = TestCollectors1.data.stream()
.collect(Collectors.reducing(0, Apple::getWeight, Integer::sum));
System.out.println(collect);
}
}
打印結(jié)果如下:
Apple [color=green, weight=210]
970
970
Stream中也提供匯聚操作reduce洗出,reduce操作強(qiáng)調(diào)是不可變性,即輸入什么類(lèi)型元素图谷,輸出還是什么類(lèi)型翩活。而Collectors提供的reducing()方法,則強(qiáng)調(diào)的是可變性便贵,輸出的類(lèi)型可以和輸入不同菠镇。
toCollection、toList與toSet
toCollection承璃、toList和toSet可以將輸入元素整理成集合:
toCollection(Supplier<C> collectionFactory):將輸入元素整理成集合利耍,collectionFactory可以指定結(jié)果集合的類(lèi)型
toList():將輸入元素整理成ArrayList
toSet():將輸入元素整理成HashSet
public class TestCollectors12 {
public static void main(String[] args) {
testToCollection();
testToList();
testToSet();
}
private static void testToCollection() {
LinkedList<Apple> result = TestCollectors1.data.stream()
.filter(item -> item.getWeight() > 150)
.collect(Collectors.toCollection(LinkedList::new));
System.out.println(result.getClass() + ":" + result);
}
private static void testToList() {
System.out.println("==============");
List<Apple> result = TestCollectors1.data.stream()
.filter(a -> a.getWeight() > 150).collect(Collectors.toList());
System.out.println(result.getClass() + ":" + result);
}
private static void testToSet() {
System.out.println("==============");
Set<String> result = TestCollectors1.data.stream()
.collect(Collectors.mapping(Apple::getColor, Collectors.toSet()));
System.out.println(result.getClass() + ":" + result);
}
}
打印結(jié)果如下:
class java.util.LinkedList:[Apple [color=green, weight=210], Apple [color=red, weight=170], Apple [color=red, weight=170], Apple [color=yellow, weight=170]]
class java.util.ArrayList:[Apple [color=green, weight=210], Apple [color=red, weight=170], Apple [color=red, weight=170], Apple [color=yellow, weight=170]]
class java.util.HashSet:[red, green, yellow]
toMap與toConcurrentMap
toMap操作可以將輸入元素整理成Map,Collectors提供三個(gè)重載的toMap()方法:
toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper):keyMapper和valueMapper分別提供結(jié)果Map的鍵和值
toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper, BinaryOperator<U> mergeFunction):mergeFunction對(duì)鍵相同的值進(jìn)行累積
toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper, BinaryOperator<U> mergeFunction, Supplier<M> mapSupplier): mapSupplier可以指定結(jié)果的Map類(lèi)型
toConcurrentMap操作同toMap,這里不再贅述隘梨。
需要注意的是程癌,只有兩個(gè)參數(shù)的toMap()(toConcurrentMap)方法的keyMapper所提供的key是不可以重復(fù)的,否則會(huì)拋出IllegalStateException轴猎。
public class TestCollectors13 {
public static void main(String[] args) {
testToMap();
testToMapWithBinaryOperatorAndSupplier();
}
private static void testToMap() {
// 報(bào)錯(cuò):java.lang.IllegalStateException
// Map<String, Integer> collect = TestCollectors1.appleList.stream()
// .collect(Collectors.toMap(Apple::getColor, Apple::getWeight));
List<Apple> data = Arrays.asList(new Apple("green", 210),
new Apple("red", 170), new Apple("yellow", 170));
Map<String, Integer> result = data.stream()
.collect(Collectors.toMap(Apple::getColor, Apple::getWeight));
System.out.println(result);
}
private static void testToMapWithBinaryOperatorAndSupplier() {
System.out.println("==============");
Hashtable<String, Integer> result = TestCollectors1.data.stream()
.collect(Collectors.toMap(Apple::getColor,
v -> 1, Integer::sum, Hashtable::new));
System.out.println(result);
}
}
打印結(jié)果如下:
{red=170, green=210, yellow=170}
{green=3, red=2, yellow=1}
————————————————
版權(quán)聲明:本文為CSDN博主「zeroxes」的原創(chuàng)文章嵌莉,遵循CC 4.0 BY-SA版權(quán)協(xié)議,轉(zhuǎn)載請(qǐng)附上原文出處鏈接及本聲明捻脖。
原文鏈接:https://blog.csdn.net/xiliunian/article/details/88773718