Collection.stream()。forEach()和Collection.forEach()

我了解使用.stream(),我可以使用类似的链操作.filter()或使用并行流。但是,如果我需要执行小的操作(例如,打印列表的元素),它们之间有什么区别?


collection.stream().forEach(System.out::println);

collection.forEach(System.out::println);


紫衣仙女
浏览 2576回答 3
3回答

慕桂英4014372

对于诸如所示的简单情况,它们基本上是相同的。但是,有许多细微的差别可能很重要。一个问题是订购。使用Stream.forEach,顺序不确定。顺序流不太可能发生,但是,它在规范中可以Stream.forEach以任意顺序执行。这确实在并行流中经常发生。相反,如果指定Iterable.forEach了Iterable,则总是按的迭代顺序执行。另一个问题是副作用。Stream.forEach必须指定中的动作为非干扰动作。(请参阅java.util.stream软件包doc。)Iterable.forEach可能具有较少的限制。对于集合java.util,Iterable.forEach通常会使用该集合的Iterator,其中大部分被设计成快速失败的,并且将抛出ConcurrentModificationException,如果集合在迭代过程中结构修饰。但是,在迭代过程中允许进行非结构化的修改。例如,ArrayList类文档说“仅设置元素的值不是结构修改”。因此,针对ArrayList.forEach允许在底层中设置值ArrayList而不会出现问题。并发集合又一次不同。它们不是快速失败,而是设计为弱一致性。完整定义在该链接上。不过,请简要考虑一下ConcurrentLinkedDeque。传递给它的操作forEach方法是允许修改底层双端队列,即使结构上,并且ConcurrentModificationException永远不会抛出。但是,发生的修改在此迭代中可能可见,也可能不可见。(因此保持“弱”一致性。)如果Iterable.forEach在同步的集合上进行迭代,则仍然可以看到另一个差异。在这样的集合上,Iterable.forEach 获取一次该集合的锁,并在对action方法的所有调用中保持该锁。该Stream.forEach调用使用集合的分隔符,该分隔符不锁定,并且依赖于不干扰的流行规则。支持该流的集合可以在迭代期间进行修改,如果是,则ConcurrentModificationException可能导致行为不一致或行为不一致。

MYYA

该答案本身与循环的各种实现的性能有关。它与被称为“非常频繁”的循环(如数百万次调用)的边际相关。在大多数情况下,循环的内容将是迄今为止最昂贵的元素。对于确实经常循环的情况,这可能仍然很有趣。您应该在目标系统下重复此测试,因为这是特定于实现的(完整的源代码)。我在快速的Linux机器上运行openjdk版本1.8.0_111。我编写了一个测试,使用此代码在列表上循环10 ^ 6次,该代码的大小各不相同integers(10 ^ 0-> 10 ^ 5个条目)。结果如下,最快的方法取决于列表中条目的数量。但是,即使在最糟糕的情况下,表现最差的人也要花10秒循环10 ^ 5个条目10 ^ 6次,因此实际上在所有情况下其他考虑因素都更为重要。public int outside = 0;private void forCounter(List<Integer> integers) {&nbsp; &nbsp; for(int ii = 0; ii < integers.size(); ii++) {&nbsp; &nbsp; &nbsp; &nbsp; Integer next = integers.get(ii);&nbsp; &nbsp; &nbsp; &nbsp; outside = next*next;&nbsp; &nbsp; }}private void forEach(List<Integer> integers) {&nbsp; &nbsp; for(Integer next : integers) {&nbsp; &nbsp; &nbsp; &nbsp; outside = next * next;&nbsp; &nbsp; }}private void iteratorForEach(List<Integer> integers) {&nbsp; &nbsp; integers.forEach((ii) -> {&nbsp; &nbsp; &nbsp; &nbsp; outside = ii*ii;&nbsp; &nbsp; });}private void iteratorStream(List<Integer> integers) {&nbsp; &nbsp; integers.stream().forEach((ii) -> {&nbsp; &nbsp; &nbsp; &nbsp; outside = ii*ii;&nbsp; &nbsp; });}这是我的时间安排:毫秒/功能/列表中的条目数。每次运行为10 ^ 6循环。&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;1&nbsp; &nbsp; 10&nbsp; &nbsp; 100&nbsp; &nbsp; 1000&nbsp; &nbsp; 10000&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;for with index&nbsp; &nbsp;39&nbsp; &nbsp;112&nbsp; &nbsp; 920&nbsp; &nbsp; 8577&nbsp; &nbsp; 89212&nbsp; &nbsp; &nbsp; &nbsp;iterator.forEach&nbsp; &nbsp;27&nbsp; &nbsp;116&nbsp; &nbsp; 959&nbsp; &nbsp; 8832&nbsp; &nbsp; 88958&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;for:each&nbsp; &nbsp;53&nbsp; &nbsp;171&nbsp; &nbsp;1262&nbsp; &nbsp;11164&nbsp; &nbsp;111005iterable.stream.forEach&nbsp; 255&nbsp; &nbsp;324&nbsp; &nbsp;1030&nbsp; &nbsp; 8519&nbsp; &nbsp; 88419如果您重复实验,我将发布完整的源代码。请编辑此答案,并在结果中加上已测试系统的注释。使用MacBook Pro,2.5 GHz Intel Core i7、16 GB,macOS 10.12.6:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;1&nbsp; &nbsp; 10&nbsp; &nbsp; 100&nbsp; &nbsp; 1000&nbsp; &nbsp; 10000&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;for with index&nbsp; &nbsp;49&nbsp; &nbsp;145&nbsp; &nbsp; 887&nbsp; &nbsp; 7614&nbsp; &nbsp; 81130&nbsp; &nbsp; &nbsp; &nbsp;iterator.forEach&nbsp; &nbsp;27&nbsp; &nbsp;106&nbsp; &nbsp;1047&nbsp; &nbsp; 8516&nbsp; &nbsp; 88044&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;for:each&nbsp; &nbsp;46&nbsp; &nbsp;143&nbsp; &nbsp;1182&nbsp; &nbsp;10548&nbsp; &nbsp;101925iterable.stream.forEach&nbsp; 393&nbsp; &nbsp;397&nbsp; &nbsp;1108&nbsp; &nbsp; 8908&nbsp; &nbsp; 88361

元芳怎么了

您提到的两者之间没有任何区别,至少从概念上讲,这Collection.forEach()只是一个简写。在内部,stream()由于创建对象,该版本的开销会更大一些,但是从运行时间来看,该版本都没有开销。两种实现都最终对collection内容进行一次迭代,并在迭代过程中打印出元素。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java