用于在流中组合两组数据.
Stream.concat(stream1, stream2).collect(Collectors.toSet());
要么
stream1.collect(Collectors.toSet()) .addAll(stream2.collect(Collectors.toSet()));
哪个更有效,为什么?
出于可读性和意图的考虑,Stream.concat(a, b).collect(toSet())
比第二种方案更清晰.
为了问题," 什么是最有效的 ",这里是一个JMH测试(我想说我没有那么多使用JMH,可能有一些空间来改进我的基准测试):
使用JMH,使用以下代码:
package stackoverflow; import java.util.HashSet; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import java.util.stream.Stream; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Fork; import org.openjdk.jmh.annotations.Measurement; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.Warmup; import org.openjdk.jmh.infra.Blackhole; @State(Scope.Benchmark) @Warmup(iterations = 2) @Fork(1) @Measurement(iterations = 10) @OutputTimeUnit(TimeUnit.NANOSECONDS) @BenchmarkMode({ Mode.AverageTime}) public class StreamBenchmark { private Sets1; private Set s2; @Setup public void setUp() { final Set valuesForA = new HashSet<>(); final Set valuesForB = new HashSet<>(); for (int i = 0; i < 1000; ++i) { valuesForA.add(Integer.toString(i)); valuesForB.add(Integer.toString(1000 + i)); } s1 = valuesForA; s2 = valuesForB; } @Benchmark public void stream_concat_then_collect_using_toSet(final Blackhole blackhole) { final Set set = Stream.concat(s1.stream(), s2.stream()).collect(Collectors.toSet()); blackhole.consume(set); } @Benchmark public void s1_collect_using_toSet_then_addAll_using_toSet(final Blackhole blackhole) { final Set set = s1.stream().collect(Collectors.toSet()); set.addAll(s2.stream().collect(Collectors.toSet())); blackhole.consume(set); } }
你得到了这些结果(为了便于阅读,我省略了一些部分).
Result "s1_collect_using_toSet_then_addAll_using_toSet": 156969,172 ±(99.9%) 4463,129 ns/op [Average] (min, avg, max) = (152842,561, 156969,172, 161444,532), stdev = 2952,084 CI (99.9%): [152506,043, 161432,301] (assumes normal distribution) Result "stream_concat_then_collect_using_toSet": 104254,566 ±(99.9%) 4318,123 ns/op [Average] (min, avg, max) = (102086,234, 104254,566, 111731,085), stdev = 2856,171 CI (99.9%): [99936,443, 108572,689] (assumes normal distribution) # Run complete. Total time: 00:00:25 Benchmark Mode Cnt Score Error Units StreamBenchmark.s1_collect_using_toSet_then_addAll_using_toSet avgt 10 156969,172 ± 4463,129 ns/op StreamBenchmark.stream_concat_then_collect_using_toSet avgt 10 104254,566 ± 4318,123 ns/op
使用的版本Stream.concat(a, b).collect(toSet())
应该更快(如果我读好JMH数字).
另一方面,我认为这个结果是正常的,因为你没有创建一个中间集(这有一些成本,即使有HashSet
),并且正如在第一个答案的评论中所述,它Stream
是懒惰的连接.
使用分析器,您可能会看到哪个部分较慢.您可能还想使用toCollection(() -> new HashSet(1000))
而不是toSet()
查看问题在于增长HashSet
内部哈希数组.