是否允许/建议重用收集器?

2022-09-01 00:28:14

我的代码中有很多地方可以做到:

someStream.collect(Collectors.toList())

其中,每次使用都会创建一个新的收集器。Collectors.toList()

这让我想到了一个问题,即是否允许并且建议做这样的事情:

private final static Collector<…> TO_LIST = Collectors.toList()

对于我使用的每种类型的类型,然后使用单个收集器,例如:

someStream.collect(TO_LIST)

当需要收集器时。

由于收集器是无状态的,只是功能和特征的集合,我应该认为它应该工作,但是OTOH在每次调用时都会创建一个新的。Collectors.toList()CollectorImpl<>

重用收集器的缺点是什么?


答案 1

我认为这更像是一个风格问题,但让我们给出一些想法:

  • 通常的做法似乎是不使用这样的 CONST 收集器对象。从这个意义上说:这样做可能会让一些读者感到惊讶,而让读者感到惊讶很少是一件好事。
  • 然后:很少有代码可以只是“复制”(可能不应该避免代码重复);但仍然:指向不同的收集器对象可能会使您更难重构或重用流构造。
  • 除此之外:你自己说过;收集器重用取决于无状态实现。因此,您使自己依赖于任何无状态的实现。可能不是问题;但也许要记住一个风险
  • 可能更重要的是:从表面上看,你的想法看起来像是一个很好的优化手段。但是,好吧;当您担心使用流的“性能影响”时,那么最终收集器创建的单个对象将“不切实际”!

我的意思是:如果你担心“浪费”绩效;您更愿意查看使用流的每一行代码,以确定该流是否正在使用“足够”的对象,以首先证明流的使用。这些流带有相当多的开销!

长话短说:Java社区尚未找到流的“标准最佳实践”;因此,我现在(个人)的两分钱:更喜欢“每个人”正在使用的那些模式 - 避免做你自己的事情。特别是当它与“性能相关”时。


答案 2

由于它基本上是一个容器,用于四个函数和特征标志,重用它没有问题,但也很少有任何优势,因为这样一个轻量级对象对内存管理的影响可以忽略不计,即使没有被优化器完全删除。Collector

不重用s的主要原因,如 内置 ,是您无法以类型安全的方式执行此操作。为任意键入的 s 提供收集器时,您需要未经检查的操作才能始终分发相同的实例。如果将 a 存储在正确类型的变量中,则无需未选中的操作即可使用,则只能将其用于一种类型的 s,以继续使用该示例。CollectorCollectorsListCollectorCollectorList

在 等的情况下,JRE开发人员走了一条不同的路,但是在引入泛型之前,常量,已经存在,我想说它们比少数可缓存的更通用,这只是其他三十多个内置收集器中的四个特殊情况,由于其函数参数而无法缓存。由于函数参数通常通过 lambda 表达式实现,lambda 表达式会生成未指定身份/相等性的对象,因此将它们映射到收集器实例的缓存将具有不可预知的效率,但效率很可能远低于内存管理器处理临时实例的效率。Collections.emptyList()EMPTY_LISTEMPTY_MAPEMPTY_SETCollectors