是否值得将 distinct() 与 collect(toSet()) 一起使用

2022-09-03 06:59:19

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

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

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


答案 1

根据javadoc,是一个有状态的中间操作。distinct

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

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


答案 2

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

来自 javadoc

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

如果您需要稳定性,那么就是.使用 after 将毫无用处(如果 API 不需要)。distinct()toSet()

但是,如果您实现了部分相等,这将非常有用: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)

  • 有了你,你不会总是有这个订单。你可能有(b,a)等。toSet()
  • 使用 distinct() 可以保留此信息,例如:.(b, a)

但是,这需要一些先决条件(顺序等)。

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


推荐