What is the difference between .foreach and .stream().foreach?
这是一个例子:
代码A:
1 2 3
| files.forEach(f -> {
//TODO
}); |
而另一个代码B可能会以此方式使用:
1
| files.stream().forEach(f -> { }); |
stream()和没有stream()两者之间有什么区别?
-
那不是很准确。 两者在语义上都等效,但是都不一定具有该实现。
-
代码A等于(文件f:文件)
-
当存在某些中间操作(映射,跳过,合并,子流,不同,过滤器,排序,限制,查看)时,应使用代码B,否则它不是最佳的。 多谢你们!
实际上,它们基本上是相同的,但是语义上的差别很小。
代码A由Iterable.forEach定义,而代码B由Stream.forEach定义。 Stream.forEach的定义允许以任何顺序处理元素-甚至对于顺序流也是如此。 (对于并行流,Stream.forEach很可能会乱序处理元素。)
Iterable.forEach从源获取一个Iterator并对其调用forEachRemaining()。据我所知,集合类上所有当前的Stream.forEach实现(JDK 8)将创建一个从源迭代器之一构建的Spliterator,然后将在该Iterator上调用forEachRemaining,就像。因此,尽管流版本具有一些额外的设置开销,但它们执行相同的操作。
但是,将来可能会改变流的实现,以致情况不再如此。
(如果要保证处理流元素的顺序,请改用forEachOrdered()。)
-
为执行的潜在更改而提出的建议可能会破坏当前合同
-
出乎意料的是,Iterable.forEach的default实现没有调用Iterator上的forEachRemaining;它只对Iterator执行。它使用for-each循环进行迭代。默认的Stream.forEach将在Spliterator上调用forEachRemaining,除非Iterable.spliterator()被覆盖(大多数JRE提供的Collection都这样做),否则最终将调用Iterator.forEachRemaining。因此,即使对于collection.forEach(…)和collection.stream().forEach(…)基本上相同的Collection,它们最终也会以不同的代码来执行。但是对于某些Collection,存在显着差异。
-
Vector存在显着差异,并且Collections.synchronized…方法返回的集合(因为其forEach实现将是synchronized),而调用stream().forEach(…)则需要手动同步。
尽管没有stream的直接实现可能会稍微更高效,但是在语义方面没有区别。
-
实际上,在语义上存在差异,例如排序保证(或在Stream.forEach情况下不存在)。
流是用于耗尽操作或迭代的一系列元素(即数据结构)。任何集合都可以作为流公开。您在流上执行的操作可以是
中间操作(map,skip,concat,substream,distinct,filter,sorted,limit,peek ..)产生另一个java.util.stream.Stream,但是中间操作是惰性操作,只有在终端操作被执行后才执行被执行。
终端操作(forEach,max,count,matchAny,findFirst,reduce,collect,sum,findAny)产生的对象不是流。
基本上,它类似于Unix中的管道。
两种方法都使用终端操作Iterable.forEach,但是带有.stream()的版本也不必要地创建表示List的stream对象。虽然没有差异,但它不是最佳的。
-
抱歉,这是不正确的。代码A确实是Iterable.forEach,但是代码B是Stream.forEach,即使对于顺序流,也不能保证以任何特定顺序处理元素。
-
@Stuart:这是API的详细信息,而自JDK 8开始,StreamSupport就将底层Iterable.forEach用于Iterable流(不包括数组)。因此,您对执行差异的可能性不存在。我的回答没错。
-
关注点不能不存在^^差异也非常真实。顺便说一句:是什么使Iterable.forEach终端?
-
@Unihedro非常可笑的是,您声称" API详细信息"可以证明您对实现详细信息的吸引力!您的陈述完全是错误的; Stream中的forEach方法与Iterable中的方法无关。 Oracle JDK当前版本中的当前实现恰好使用了Iterable,但是这几乎无关紧要,因为您不能指望保持不变。您只能依赖API规范。
-
@BrianGoetz我必须在我的回复之前加上Stream.forEach的javadocs说的事实:"对此流的每个元素执行一个操作。...此操作的行为明确地是不确定的。"缺乏保证并不意味着不能在非并行流中使用forEach。 zeroflag链接了一个有关如何产生影响的相关示例,但它显式使用并行流,其中流作为Iterables的表示...
-
...被实现为StreamSupport中的Spliterators,它调用Iterable的基础forEach操作。虽然Stream.forEach的当前实现可以随时间变化,但是Iterable.forEach也会随时间变化。那根本没有打到问的问题。
-
在当前实现中,Stream.forEach不会调用Iterable.forEach。这很容易证明:new ArrayList(){ @Override public void forEach(Consumer super String> c) { System.out.println("Iterable.forEach"); } }.stream().forEach(x->{});将不打印消息…