繁体   English   中英

Collectors.toSet实现细节

[英]Collectors.toSet implementation detail

我在Jdk-8下看了Collectors.toSet实现,几乎看到了显而易见的事情:

 public static <T> Collector<T, ?, Set<T>> toSet() {
    return new CollectorImpl<>(
       (Supplier<Set<T>>) HashSet::new, 
       Set::add,
       (left, right) -> { left.addAll(right); return left; }, // combiner
       CH_UNORDERED_ID);

看一下combiner片刻; 这之前已经讨论了这里 ,但这个想法是a combiner folds from the second argument into the first 这显然发生在这里。

但后来我查看了jdk-9实现并看到了这个:

 public static <T> Collector<T, ?, Set<T>> toSet() {
    return new CollectorImpl<>(
       (Supplier<Set<T>>) HashSet::new, 
       Set::add,
       (left, right) -> {
          if (left.size() < right.size()) {
            right.addAll(left); return right;
          } else {
             left.addAll(right); return left;
          }
       },
       CH_UNORDERED_ID);

现在为什么会发生这种情况有点明显 - 将less elements to a bigger Set, then the other way around添加less elements to a bigger Set, then the other way around需要更少的时间,反之亦然。 但这是否比普通的addAll便宜,考虑分支的额外开销呢?

这也打破了关于总是向左折叠的法律 ......

有人能在这里说清楚吗?

Collector器的组合器功能将适当地接收 leftright ,如果存在要维护的遭遇顺序, Collector决定它将如何实际组合这两个参数。

文件说明:

一个接受两个部分结果并合并它们的函数。 组合器函数可以将状态从一个参数折叠到另一个参数并返回该参数,或者可以返回新的结果容器。

为了收集List ,如果我们只是将left.addAll(right)交换到right.addAll(left) ,那将是灾难性的,但是对于无序Set ,它并不重要。 toSet()收集器甚至报告UNORDERED特性以提示Stream (或任何客户端代码),它甚至不会将哪个参数提供为leftright ,因此并行流可以组合任意部分结果,无论什么已完成首先,换句话说,它可能表现得像一个无序流,即使源有一个遭遇顺序(Java 8的实现不使用那个机会)。

关于它是否值得...我们正在比较一个额外的分支与可能保存的数千个add操作, 每个分支在内部承载多个条件分支...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM