javastream序号_学习Java8StreamApi(4)-Stream终端操作
之c。。。
Stream API
上篇内容我们学习了Stream的⼤部分终端操作,我们这篇着重了解下Stream中重要的终端操作:collect。
collect ⽅法
序号
⽀持的类
⽅法定义
⽅法说明
1
Stream
R collect(Suppliersupplier, BiConsumer accumulator, BiConsumer combiner);
对此流的元素执⾏ mutable reduction操作。
2
Stream
R collect(Collector super T, A, R> collector);
使⽤ Collector对此流的元素执⾏ mutable reduction Collector。
以下代码见 StreamTerminalOperationTransformTest。
实现3参数转换接⼝
序号1的⽅法,传递了3个参数,参数1为创建新结果容器的函数;参数2为累加器函数,将参数1和流内元素执⾏累加操作;参数3为组合器函数,并⾏执⾏时会使⽤该函数。
同步执⾏时,该⽅法相当于执⾏:
R result = ();
for (T element : this stream) {
accumulator.accept(result, element);
}
return result;
我们编写如下代码,看下实际效果
// 使⽤collect⽅法实现字符串连接
log.info("拼接字符串为:{}",
Stream.of("I", "love", "you", "too")
.collect(StringBuilder::new, (b1, b2) -> {
log.info("累加执⾏:{} + {}", b1, b2);
b1.append(b2);
}, (b1, b2) -> {
log.info("组合执⾏:{} ++ {}", b1, b2);
b1.append(b2);
})
.toString());
以上代码将输出如下⽇志:
[main] web.flux.stream.StreamTerminalOperationTransformTest - 累加执⾏: + I
[main] web.flux.stream.StreamTerminalOperationTransformTest - 累加执⾏:I + love
[main] web.flux.stream.StreamTerminalOperationTransformTest - 累加执⾏:Ilove + you
[main] web.flux.stream.StreamTerminalOperationTransformTest - 累加执⾏:Ilo
veyou + too
[main] web.flux.stream.StreamTerminalOperationTransformTest - 拼接字符串为:Iloveyoutoo
并⾏执⾏时,该⽅法相当于执⾏:
R result1 = ();
R result2 = ();
R result3 = ();
R result4 = ();
// 累加执⾏,此处为并发(多线程)执⾏,每⾏代表⼀个线程
accumulator.accept(result1, element1);
accumulator.accept(result2, element2);
accumulator.accept(result3, element3);
accumulator.accept(result4, element4);
// ...
// accumulator.accept(resultN, elementN);
// 开始组合,此处为并发(多线程)执⾏,每⾏代表⼀个线程
combiner.accept(result1, result2);
combiner.accept(result3, result4);
combiner.accept(result1, result3);
// combiner.accept(result1, resultN);
return result1;
将上述的代码改为.parallel()⽅式调⽤,将输出如下⽇志:
[main] web.flux.stream.StreamTerminalOperationTransformTest - 累加执⾏: + you
[ForkJoinPoolmonPool-worker-3] web.flux.stream.StreamTerminalOperationTransformTest - 累加执⾏: + I
[ForkJoinPoolmonPool-worker-2] web.flux.stream.StreamTerminalOperationTransformTest - 累加执⾏: + too
[ForkJoinPoolmonPool-worker-2] web.flux.stream.StreamTerminalOperationTransformTest - 组合执⾏:you ++ too
[ForkJoinPoolmonPool-worker-1] web.flux.stream.StreamTerminalOperationTransformTest - 累加执⾏: + love
[ForkJoinPoolmonPool-worker-1] web.flux.stream.StreamTerminalOperationTransformTest - 组合执⾏:I ++ love
[ForkJoinPoolmonPool-worker-1] web.flux.stream.StreamTerminalOperationTransformTest - 组合执⾏:Ilove ++ youtoo
[main] web.flux.stream.StreamTerminalOperationTransformTest - 拼接字符串为:Iloveyoutoo
注意:上述⽇志中出现的ForkJoinPoolmonPool-worker-N为并发(多线程)执⾏时的线程名。
实现Collector接⼝
实现Collector需要实现如下4个接⼝:
// ⼀个创建并返回⼀个新的可变结果容器的函数。
Supplier supplier();
// 将值折叠成可变结果容器的函数。
BiConsumer accumulator();
// ⼀个接受两个部分结果并将其合并的函数。
BinaryOperator combiner();
// 执⾏从中间累积类型 A到最终结果类型 R的最终 R 。
Function finisher();
/
/ 返回⼀个 Collector.Characteristics 类型的Set, 表⽰该收集容器的特征。
Set characteristics();
collect⽅法执⾏时,他们的调⽤流程如下:
创建新的结果容器(supplier())
将新的数据元素并⼊结果容器(accumulator())
将两个结果容器组合成⼀个(combiner())
在容器上执⾏可选的最终变换(finisher())
简单来讲,⽣成容器A,通过accumulator针对A及流元素T执⾏累加,(如果并⾏存在的话)对多个A执⾏组合combiner,最终执⾏finisher 后由A转换为R。对于使⽤者来说,A为中间变量,⽆关其实现细节。
我们实现⼀个计算整数流的平均数的Collector,代码如下:
// 使⽤collector实现求ping均值
log.info("[1, 2, 3, 4, 5, 6]的平均值:{}",
Stream.of(1, 2, 3, 4, 5, 6)
.parallel()
.collect(new Collector() {
@Override
public Supplier supplier() {
return () -> new long[2];
}
@Override
public BiConsumer accumulator() {
return (a, t) -> {
log.info("{}累加{}", a, t);
a[0] += t;
a[1]++;
};
}
@Override
public BinaryOperator combiner() {
return (a, b) -> {
log.info("{}组合{}", a, b);
a[0] += b[0];
a[1] += b[1];
return a;
};
}
@Override
public Function finisher() {
return (a) -> a[1] == 0 ? 0 : new Long(a[0]).doubleValue() / a[1]; }
@Override
public Set characteristics() {
Set set = new HashSet<>();
set.add(Characteristics.CONCURRENT);
return set;
}
}
)
);
常⽤Collector
通过上⾯的⽰例,我们实现了⼀个⾃定义的Collector,我们发现实现⼀个⾃定义的Collector还是⽐较⿇烦的,需要实现5个接⼝。
Java 开发者们已经想到了这个问题,他们额外提供了⼀个 of ⽅法,可以通过lambda的⽅式创建 collector,类似 collect 中传递⼏个参数:提供者、累加器、组合器、完成器以及特征配置,此处我们就不细讲了。
Java 开发者们更为贴⼼的为我们创建了⼀些常⽤的 Collector ,让我们可以直接使⽤。这些常⽤的 Collector 实现放在 Collectors 类下,我们来了解下。
统计平均值 averagingXxx 的使⽤
Collectors 提供了 averagingDouble、averagingLong、averagingInt 3种统计平均值的 Collector 实现类,以下代码以 averagingInt 为例,由于使⽤⽅式相似,我们就不举例了。
// 使⽤collector实现求均值
log.info("[1, 2, 3, 4, 5, 6]的平均值:{}",
Stream.of(1, 2, 3, 4, 5, 6)
.collect(Collectors.averagingInt(n -> n))
);
统计元素个数 counting 的使⽤
该⽅法和 Stream 中的 count ⽅法⼀样。
// 使⽤collector获取元素数量
log.info("[1, 2, 3, 4, 5, 6]的个数:{}",
Stream.of(1, 2, 3, 4, 5, 6)
.unting())
);
统计总和 summingXxx 的使⽤
Collectors 提供了 summingDouble、summingLong、summingInt 3种统计求和值的 Collecto r实现类,同时还提供了summarizingDouble 、 summarizingLong 、summarizingInt 3种统计对象的 Collector 实现类,以下代码以 summingInt 为例,由于使⽤⽅式相似,我们就不举例了。
// 使⽤collector获取总和
log.info("[1, 2, 3, 4, 5, 6]的总和:{}",
Stream.of(1, 2, 3, 4, 5, 6)
.collect(Collectors.summingInt(n -> n))
);
统计最⼩元素 minBy 的使⽤
// 使⽤collector获取最⼩元素
log.info("[1, 2, 3, 4, 5, 6]的最⼩值:{}",
Stream.of(1, 2, 3, 4, 5, 6)
java stream.collect(Collectors.minBy(Integer::min))
.get()
);
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论