Stream.of(item).collect(Collectors.toSomeCollection())比新的SomeCollection(Arrays.asList(item))更快吗?

Kar*_*ter 1 java collections java-stream

Java 8提供

Stream.of(item).collect(Collectors.toSomeCollection())
Run Code Online (Sandbox Code Playgroud)

例如Stream.of("abc").collect(Collectors.toSet()).避免相对昂贵的new操作员在窗帘前快速

new SomeCollection(Arrays.asList(item))
Run Code Online (Sandbox Code Playgroud)

例如new HashSet<>(Arrays.asList("abc"))

我确信不同集合的初始化new具有不同的成本(哈希集在准备使用之前需要哈希表,数组列表是分配的数组,而链表不需要这样).

我试图弄清楚流相关类是否在new内部避免,但OpenJDK代码很难理解.我认为如果我将其Stream.of视为已初始化的管道和使用可重用功能的收集器,它们就可以了.

可能是反过来了吗?

Jor*_*nee 8

让我们测量(使用jmh)并找出哪一个'更快':

@BenchmarkMode({ Mode.AverageTime })
@Warmup(iterations = 10)
@Measurement(iterations = 10)
@Fork(1)
public class MyBenchmark {

    private static final int ITERATIONS = 10_000_000;

    @Benchmark
    public void baseLine(Blackhole bh) {
        for (int i = 0; i < ITERATIONS; i++) {
            Set<String> s = new HashSet<>();
            s.add("A");
            bh.consume(s);
        }
    }

    @Benchmark
    public void asList(Blackhole bh) {
        for (int i = 0; i < ITERATIONS; i++) {
            Set<?> s = new HashSet<>(Arrays.asList("A"));
            bh.consume(s);
        }
    }

    @Benchmark
    public void collectStream(Blackhole bh) {
        for (int i = 0; i < ITERATIONS; i++) {
            Set<?> s = Stream.of("A").collect(Collectors.toSet());
            bh.consume(s);
        }
    }

    @Benchmark
    public void setOf(Blackhole bh) {
        for (int i = 0; i < ITERATIONS; i++) {
            Set<?> s = Set.of("A");
            bh.consume(s);
        }
    }

    @Benchmark
    public void singletonCollection(Blackhole bh) {
        for (int i = 0; i < ITERATIONS; i++) {
            Set<?> s = Collections.singleton("A");
            bh.consume(s);
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

结果是:

# JMH version: 1.19
# VM version: JDK 9, VM 9+181

Benchmark                        Mode  Cnt  Score   Error  Units
MyBenchmark.baseLine             avgt   10  0.301 ± 0.002   s/op
MyBenchmark.asList               avgt   10  0.350 ± 0.012   s/op    
MyBenchmark.collectStream        avgt   10  0.517 ± 0.009   s/op
MyBenchmark.setOf                avgt   10  0.057 ± 0.001   s/op
MyBenchmark.singletonCollection  avgt   10  0.057 ± 0.001   s/op
Run Code Online (Sandbox Code Playgroud)

所以在你提到的2中,使用asList似乎更快.如果您只有一个元素,则可以使用Collections.singleton*(如@AndyTurner所建议的那样).Java 9接口工厂方法适用于任意数量的元素,但也针对单个元素进行了优化.

  • 这是找出你真正需要的确切方法(或者很好奇并且不想使用生产代码中最易读的版本).结果在计算机上以及运行基准测试的条件和一个元素的集合中是有效的. (2认同)