繁体   English   中英

使用distinct()和collect(toSet())是否值得

[英]Is it worth using distinct() with collect(toSet())

将流的元素收集到集合中时,是否还有优势(或缺点)在流上指定.distinct() 例如:

return items.stream().map(...).distinct().collect(toSet());

鉴于该集合已经删除了重复项,这似乎是多余的,但它是否提供任何性能优势或劣势? 答案取决于流是并行/顺序还是有序/无序?

根据javadocdistinct是一个有状态的中间操作。

如果你确实有.distinct紧跟着.collect ,那么它并没有真正增加任何好处。 也许如果.distinct实现比Set重复检查更.distinct ,你可能会获得一些好处,但是如果你收集到一个集合,你最终会得到相同的结果。

另一方面,如果.distinct发生在.map操作之前,并且该特定映射是一项昂贵的操作,那么您可能会获得一些收益,因为您整体处理的数据较少。

虽然你有相同的结果,但它们不会做同样的事情: toSet()使用HashSet ,你失去了初始排序,如果需要,它可以保留不同的东西:

来自javadoc

保持并行管道中不同()的稳定性相对昂贵(要求操作充当完全屏障,具有大量缓冲开销),并且通常不需要稳定性。 如果您的情境的语义允许,使用无序流源(例如generate(Supplier))或使用BaseStream.unordered()删除排序约束可以显着提高并行管道中distinct()的执行效率。 如果需要与遇到顺序的一致性,并且您在并行管道中使用distinct()遇到性能不佳或内存利用率,则切换到使用BaseStream.sequential()的顺序执行可能会提高性能。

如果你需要稳定性,那么它是distinct() 之后使用toSet()将是无用的(如果API不需要)。

但是,如果你有一个equals实现部分相等的equals

class F {
  int a;
  int b;
  @Override int hashCode() {return Objects.hashCode(a);}
  @Override boolean equals(Object other) {
    if (other == this) return true;
    if (!(other instanceof F)) return false;
    return a == ((F)other).a;
  }
}

如果你有a = F(10, 1)b = F(10, 2)它们是等于。 但并非所有领域都是平等的。

如果在列表中你有(b, a)

  • 使用toSet()您将无法始终拥有此订单。 你可能有(b,a)等
  • 使用distinct()可以保留此信息,例如: (b, a)

然而,这假设了一些先决条件(顺序等)。

注意:这可以使用TreeSet和适当的compareTo方法完成。

distinct会调用equals / hashcode来分隔项目,之后toSet会做同样的事情(即使在不需要之后,但是toSet也不能真正知道),所以基本上你只是重复调用。 它应该表现稍差IMO。 测量也很容易。

暂无
暂无

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

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