java中流的优点_Java 8顺序流有直接或间接的性能优势吗?

首先,除特殊情况外,例如省略多余的排序操作或在count()上返回已知大小,操作的时间复杂度通常不会改变,因此执行时间上的所有差异通常都是一个恒定的偏移量.或(相当小的)因素,而不是根本的变化.

您始终可以编写一个手动循环,其操作基本上与Stream内部实现的操作相同.因此,内部优化(如this answer所述)总是可以通过“但我可以在循环中执行相同的操作”来忽略.

但是……当我们将“流”与“循环”进行比较时,假设针对特定用例以最有效的方式编写所有手动循环是否真的合理?无论调用代码作者的经验水平如何,特定的Stream实现都会将其优化应用于所有适用的情况.我已经看到循环丢失了短路或执行特定用例不需要的冗余操作的机会.

另一个方面是执行某些优化所需的信息. Stream API围绕Spliterator接口构建,该接口可以提供源数据的特征,例如它允许找出数据是否具有有意义的顺序(某些操作需要保留),或者是否已经按照自然顺序或使用特定的比较器进行了预排序.当可以预测时,它还可以提供预期的元素数量,作为估计或精确值.

接收一个任意Collection的方法以实现具有普通循环的算法,将很难找出是否存在这样的特征. List表示有意义的顺序,而Set通常不会,除非它是SortedSet或LinkedHashSet,而后者是特定的实现类,而不是接口.因此,针对所有已知星座的测试可能仍会错过第三方协议的实现,而第三方协议的实现无法通过预定义的界面来表达.

当然,从Java 8开始,您可以自己购买一个Spliterator来检查这些特性,但这将使您的循环解决方案变成一件不平凡的事情,并且还意味着重复已经使用Stream API完成的工作.

基于Spliterator的流解决方案与常规循环之间还有另一个有趣的区别,当迭代数组以外的内容时使用Iterator.模式是在迭代器上调用hasNext,然后调用next,除非hasNext返回false.但是Iterator的合同没有强制采用这种模式.已知成功的情况下(例如,您已经知道集合的大小),调用者可以在没有hasNext的情况下调用next,甚至多次.同样,如果调用者不记得上一次调用的结果,则调用者可以多次调用hasNext而不调用next.

结果,迭代器实现必须执行冗余操作,例如.有效地检查循环条件两次,一次在hasNext中,返回一个布尔值,一次在下一次,当不满足时抛出NoSuchElementException.通常,hasNext必须执行实际的遍历操作并将结果存储到Iterator实例中,以确保结果保持有效,直到后续的下一次调用为止.接下来的下一个操作必须检查这种遍历是否已经发生,或者是否必须执行该操作本身.实际上,热点优化器可能消除也可能不会消除迭代器设计带来的开销.

相反,分离器具有单个遍历方法,布尔型tryAdvance(Consumer< super T>动作),该方法执行实际操作并返回是否存在元素.这大大简化了循环逻辑.对于非短路操作,甚至还有forEachRemaining(Consumer&lt ;? super T>动作)的空白,这允许实际的实现提供整个循环逻辑.例如,在ArrayList的情况下,该操作将结束于对索引的简单计数循环,从而执行纯数组访问.

您可以将此类设计与例如BufferedReader的readLine()执行操作并在最后一个元素之后返回null;或regex Matcher的find()进行搜索,更新匹配器的状态并返回成功状态.

但是,在专门设计用于识别和消除冗余操作的优化器的环境中,很难预测这种设计差异的影响.得出的结论是,基于流的解决方案有可能变得更快,尽管它取决于很多因素,是否会在特定情况下实现.如开始时所说,通常不会更改整体时间复杂度,这是值得担心的.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值