首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Collectors.toSet实现细节

Collectors.toSet实现细节
EN

Stack Overflow用户
提问于 2017-05-03 18:38:09
回答 1查看 485关注 0票数 6

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

代码语言:javascript
复制
 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实现,并看到了以下内容:

代码语言:javascript
复制
 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所需的时间更少。但是这真的比普通的addAll便宜吗,考虑一下这个分支的额外开销吧?

而且这违反了我关于总是折叠左边的定律..。

有人能在这里亮点光吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-05-03 19:19:06

Collector的组合器函数将适当地接收leftright,如果存在需要维护的相遇顺序,则取决于Collector,它将如何实际组合这两个参数。

文档指出:

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

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

关于它是否值得,…我们将单个附加分支与我们可以保存的数千个add操作进行比较,每个操作在内部都包含多个条件分支(…)。

票数 11
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43767685

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档