如何使用 "same" 收集器使用多个 Stream,而不连接它们?
How to consume more than one Stream with the "same" Collector, without concatenating them?
假设我们有一个 Collector
, and we want to feed it the contents of a succession of Stream
s。
最自然的做法是 concatenating the Stream
s and feeding the Collector
with the concatenation. But this might not be optimal: for example, if each Stream
reads from a scarce resource allocated with a try-with-resources,同时拥有所有 Stream
会很昂贵。
此外,有时我们甚至可能无法直接访问 Stream
s,我们可能只有一个不透明的方法“提供”它作为参数接收的 Collector
,并且 returns结果。
在这些情况下,如何从多个来源喂养 Collector
?
一种解决方案是使用此辅助 duplicate
函数:
static <T,A,R> Collector<T,A,Collector<T,A,R>> duplicate(Collector<T,A,R> collector) {
final Supplier<A> supplier = collector.supplier();
final BiConsumer<A, T> accumulator = collector.accumulator();
final BinaryOperator<A> combiner = collector.combiner();
final Function<A, R> finisher = collector.finisher();
final Function<A, Collector<T,A,R>> newFinisher = (finalState) ->
Collector.of(() -> finalState, accumulator, combiner, finisher);
return Collector.of(supplier,accumulator,combiner,newFinisher);
}
duplicate
接受一个 Collector
和 returns 一个 Collector
就像第一个一样,除了它不是原始结果类型,而是 returns 另一个 Collector
作为结果,我们稍后可以传递给进一步 Stream
s:
public static void main( String[] args )
{
final Collector<Integer, ?, Integer> summy0 =
Collectors.summingInt(i -> i);
final Collector<Integer, ?, Integer> summy1 =
Stream.<Integer>of(1, 2, 3).collect(duplicate(summy0));
final Collector<Integer, ?, Integer> summy2 =
Stream.<Integer>of(4, 5, 6).collect(duplicate(summy1));
System.out.println(Stream.<Integer>of().collect(summy2));
}
而不是 concatenating Stream
s that have been previously allocated with a try-with-resources, a possible solution is to splice them in a "top-level" Stream
using flatMap
,然后使用 Collector
.
使用生成的 Stream
for safe resource handling with Stream
s is to use try-with-resources。然而,flatMap
在这方面表现特殊:它本身确保拼接的子 Stream
关闭,both 当它们在主中“耗尽”时Stream
,当Stream
异常中断时。
在我看来,flatMap
javadocs 中的措辞对于异常情况下的清理感觉有点模棱两可:
Each mapped stream is closed after its contents have been placed into this stream.
但是这个实验表明,即使出现异常,sub-Stream
s 也会关闭:
// This prints "closed!" before the stack trace
Stream.of(1,2,3)
.flatMap((i) ->
Stream.<String>generate(() -> { throw new RuntimeException(); })
.limit(2)
.onClose(() -> System.err.println("closed!"))
).forEach(System.err::println);
假设我们有一个 Collector
, and we want to feed it the contents of a succession of Stream
s。
最自然的做法是 concatenating the Stream
s and feeding the Collector
with the concatenation. But this might not be optimal: for example, if each Stream
reads from a scarce resource allocated with a try-with-resources,同时拥有所有 Stream
会很昂贵。
此外,有时我们甚至可能无法直接访问 Stream
s,我们可能只有一个不透明的方法“提供”它作为参数接收的 Collector
,并且 returns结果。
在这些情况下,如何从多个来源喂养 Collector
?
一种解决方案是使用此辅助 duplicate
函数:
static <T,A,R> Collector<T,A,Collector<T,A,R>> duplicate(Collector<T,A,R> collector) {
final Supplier<A> supplier = collector.supplier();
final BiConsumer<A, T> accumulator = collector.accumulator();
final BinaryOperator<A> combiner = collector.combiner();
final Function<A, R> finisher = collector.finisher();
final Function<A, Collector<T,A,R>> newFinisher = (finalState) ->
Collector.of(() -> finalState, accumulator, combiner, finisher);
return Collector.of(supplier,accumulator,combiner,newFinisher);
}
duplicate
接受一个 Collector
和 returns 一个 Collector
就像第一个一样,除了它不是原始结果类型,而是 returns 另一个 Collector
作为结果,我们稍后可以传递给进一步 Stream
s:
public static void main( String[] args )
{
final Collector<Integer, ?, Integer> summy0 =
Collectors.summingInt(i -> i);
final Collector<Integer, ?, Integer> summy1 =
Stream.<Integer>of(1, 2, 3).collect(duplicate(summy0));
final Collector<Integer, ?, Integer> summy2 =
Stream.<Integer>of(4, 5, 6).collect(duplicate(summy1));
System.out.println(Stream.<Integer>of().collect(summy2));
}
而不是 concatenating Stream
s that have been previously allocated with a try-with-resources, a possible solution is to splice them in a "top-level" Stream
using flatMap
,然后使用 Collector
.
Stream
Stream
s is to use try-with-resources。然而,flatMap
在这方面表现特殊:它本身确保拼接的子 Stream
关闭,both 当它们在主中“耗尽”时Stream
,当Stream
异常中断时。
在我看来,flatMap
javadocs 中的措辞对于异常情况下的清理感觉有点模棱两可:
Each mapped stream is closed after its contents have been placed into this stream.
但是这个实验表明,即使出现异常,sub-Stream
s 也会关闭:
// This prints "closed!" before the stack trace
Stream.of(1,2,3)
.flatMap((i) ->
Stream.<String>generate(() -> { throw new RuntimeException(); })
.limit(2)
.onClose(() -> System.err.println("closed!"))
).forEach(System.err::println);