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

时间:2016-05-06 02:58:39

标签: java java-8 java-stream

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

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

像这样使用

Set<Foo> fooSet = myFooStream.collect(toSetSized(100000));

我担心Collectors.toSet()的实施会设置Characteristics枚举Collectors.toCollection()不会:Characteristics.UNORDEREDCollectors.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});
}

所以这是我的问题:  1.这是我为自定义toSet()这样简单的东西创建无序收集器的唯一选择吗  2.如果我想让它理想地工作,是否有必要应用无序特征?我已经阅读了a question on this forum,在那里我了解到无序特征不再向后传播到流中。它仍然有用吗?

1 个答案:

答案 0 :(得分:4)

首先,UNORDERED的{​​{1}}特征可以帮助提高性能,而不是其他任何东西。 Collector没有这个特征,但不依赖于遭遇顺序,没有任何问题。

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

因此,更重要的问题是不要阻止这种潜在的优化(可能在将来)有多重要。

请注意,还有其他未指定的实现细节,影响了第二个变体的潜在优化。 Collector收集器具有未指定的内部工作方式,仅保证提供toCollection(Supplier)生成的类型的最终结果。相比之下,Supplier精确地定义了收集者应该如何工作,也可能阻碍收集生成未来版本的收集者的内部优化。

因此,在不触及Collector.of(() -> new HashSet<>(initialCapacity), Set::add, (c1, c2) -> { c1.addAll(c2); return c1; }, IDENTITY_FINISH, UNORDERED)的其他方面的情况下指定特征的方法将是最佳解决方案,但据我所知,现有API没有提供简单的方法。但是你自己很容易建立这样的设施:

Collector

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

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);
}

或提供您的工厂方法

HashSet<String> set=stream
    .collect(characteristics(toCollection(()->new HashSet<>(capacity)), UNORDERED));

这限制了提供你的特征所需的努力(如果它是一个反复出现的问题),所以提供它们也不会有害,即使你不知道它会产生多大的影响。