尽可能在收集器中使用Characteristics.UNORDERED很重要吗?

Han*_*k D 7 java java-8 java-stream

由于我使用了很多流,其中一些处理大量数据,我认为预先分配基于集合的收集器大小是一个好主意,以防止随着集合的增长而进行昂贵的重新分配.所以我想出了这个,以及类似的其他集合类型:

public static <T> Collector<T, ?, Set<T>> toSetSized(int initialCapacity) {
    return Collectors.toCollection(()-> new HashSet<>(initialCapacity));
}
Run Code Online (Sandbox Code Playgroud)

像这样使用

Set<Foo> fooSet = myFooStream.collect(toSetSized(100000));
Run Code Online (Sandbox Code Playgroud)

我担心的是,实现Collectors.toSet()设置一个没有的Characteristics枚举Collectors.toCollection():Characteristics.UNORDERED.没有方便的变体Collectors.toCollection()来设置超出默认值的所需特性,并且Collectors.toSet()由于可见性问题我无法复制实现.所以,为了设置这个UNORDERED特性我不得不这样做:

static<T> Collector<T,?,Set<T>> toSetSized(int initialCapacity){
    return Collector.of(
            () -> new HashSet<>(initialCapacity),
            Set::add,
            (c1, c2) -> {
                c1.addAll(c2);
                return c1;
            },
            new Collector.Characteristics[]{IDENTITY_FINISH, UNORDERED});
}
Run Code Online (Sandbox Code Playgroud)

所以这是我的问题:1.这是我唯一的选择,为简单的自定义toSet() 2 创建无序收集器.如果我希望这个理想地工作,是否有必要应用无序特征?我在这个论坛上读到了一个问题,在那里我了解到无序特征不再向后传播到Stream中.它仍然有用吗?

Hol*_*ger 5

首先, a 的UNORDERED特性Collector是为了提高性能而不是别的。Collector没有那个特征但不取决于遭遇顺序并没有错。

这个特性是否有影响取决于流操作本身和实现细节。虽然当前的实现可能不会从中汲取太多优势,但由于反向传播的困难,这并不意味着未来的版本不会。当然,这已经是无序的流,不会受到所述UNORDERED的特性Collector。并不是所有的流操作都有可能从中受益。

所以更重要的问题是不阻止这种潜在的优化(也许在未来)有多重要。

请注意,还有其他未指定的实现细节,会影响您的第二个变体时的潜在优化。该toCollection(Supplier)收集器具有未指定的内部工作,只保证提供所生产的类型的最终结果Supplier。相比之下,Collector.of(() -> new HashSet<>(initialCapacity), Set::add, (c1, c2) -> { c1.addAll(c2); return c1; }, IDENTITY_FINISH, UNORDERED)精确定义了收集器应该如何工作,也可能会阻碍未来版本的收集器生产收集器的内部优化。

因此,在不涉及 a 的其他方面的情况下指定特征的方法Collector将是最佳解决方案,但据我所知,现有 API 没有提供简单的方法。但是自己构建这样的设施很容易:

public static <T,A,R> Collector<T,A,R> characteristics(
                      Collector<T,A,R> c, Collector.Characteristics... ch) {
    Set<Collector.Characteristics> o = c.characteristics();
    if(!o.isEmpty()) {
        o=EnumSet.copyOf(o);
        Collections.addAll(o, ch);
        ch=o.toArray(ch);
    }
    return Collector.of(c.supplier(), c.accumulator(), c.combiner(), c.finisher(), ch);
}
Run Code Online (Sandbox Code Playgroud)

用这种方法,很容易说,例如

HashSet<String> set=stream
    .collect(characteristics(toCollection(()->new HashSet<>(capacity)), UNORDERED));
Run Code Online (Sandbox Code Playgroud)

或提供您的工厂方法

public static <T> Collector<T, ?, Set<T>> toSetSized(int initialCapacity) {
    return characteristics(toCollection(()-> new HashSet<>(initialCapacity)), UNORDERED);
}
Run Code Online (Sandbox Code Playgroud)

这限制了提供您的特征所需的努力(如果它是一个反复出现的问题),因此提供它们不会有什么坏处,即使您不知道它会产生多大影响。