当前位置: 首页> 教育> 高考 > 详谈 Java中的list.forEach()和list.stream().forEach() 异同点

详谈 Java中的list.forEach()和list.stream().forEach() 异同点

时间:2025/7/14 5:11:13来源:https://blog.csdn.net/huo065000/article/details/139268136 浏览次数:0次

涉及的文章链接:ArrayList 循环Remove遇到的坑

一、想总结本篇博客的原因

在这里插入图片描述
在日常开发中,需要对集合数据进行或多或少的赋值修改,那么循环赋值或者做一些处理就是最常见的一种操作了,但是用习惯了stream流,所以在循环的过程中就很习惯的使用stream.forEach的方式,可是编码规范却提示用.forEach代替,这是为何呢?

二、stream.forEach 和 .forEach都所处何处?

1).forEach

去定位代码位置,就会发现其在java.lang包下,list.forEach则属于最基本的操作了。因为是基本操作,所以它并不支持并行处理,因此它在处理大量数据时可能不如Stream API高效。

2)stream.forEach

所属java.util.stream下,是Stream API的一部分,用于对流中的每个元素执行给定的操作。使用Stream API的 forEach 允许进行更多的操作,例如过滤、映射等。Stream API提供了更多的灵活性和功能,适用于处理大量数据或进行复杂的操作。

三、stream.forEach 和 .forEach 代码示例

public static void main(String[] args) {List<String> list= Arrays.asList("Sunday","Monday","TuesDay","WednesDay","ThursDay","Friday","Saturday");list.forEach(d-> System.out.println("value:"+d));list.stream().forEach(f-> System.out.println("value1:"+f));list.stream().filter(d->d.length()>3).forEach(s-> System.out.println("value3:"+s));}

在这里插入图片描述

—总结差异使用

如上demo,当时普通的循环输出的时候,idea会提示我们使用.forEach来替代.stream.forEach,因为仅仅是简单的输出或者赋值,再无其他的操纵;但是当需要对集合做一些额外处理,比如筛选的时候,我们仅仅用.forEach则满足不了需求了,需要先提前将list进行筛选,再进行forEach操作;

四、 parallelStream.forEach

1)parallelStream

表面含义理解也能晓得相比stream而言,他是一种并行的流。它通过 Fork/Join 框架来拆分任务,加速流的处理过程。Fork/Join 的框架是通过把一个大任务不断 fork 成许多子任务,然后多线程执行这些子任务,最后再 Join 这些子任务得到最终结果。

2)parallelStream.forEach demo

① 性能方向

public static void main(String[] args) {List<Integer> numberList=new ArrayList<>();for (int i=0;i<1000000;i++){numberList.add(i);}Long startTime=System.currentTimeMillis();List<Integer> parallelList=new ArrayList<>();numberList.parallelStream().forEach(d->{double powValue= Math.pow(d,3);});Long endTime=System.currentTimeMillis();System.out.println("parallel:"+(endTime-startTime));}

②准确性方向

public static void main(String[] args) {List<Integer> numberList=new ArrayList<>();for (int i=0;i<10000;i++){numberList.add(i);}System.out.println("size="+numberList.size());List<Integer> parallelList=new ArrayList<>();numberList.parallelStream().forEach(parallelList::add);System.out.println("size parallel="+parallelList.size());}

看如上代码,执行结果会是什么呢?是size和size parallel都是10000,还是其他?可以自行测试一下,我测试的结果是报错了。

size=10000
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 4605at java.util.ArrayList.add(ArrayList.java:465)at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1384)at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)at java.util.stream.ForEachOps$ForEachTask.compute(ForEachOps.java:290)at java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:731)at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)at java.util.concurrent.ForkJoinTask.doInvoke(ForkJoinTask.java:401)at java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:734)at java.util.stream.ForEachOps$ForEachOp.evaluateParallel(ForEachOps.java:159)at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateParallel(ForEachOps.java:173)at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:233)at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:485)at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:650)at com.meta.image.user.service.impl.AchievementServiceImpl.main(AchievementServiceImpl.java:1159)

注:报错分析详情下篇博客。

五、stream.forEach 和 .forEach的CRUD操作

1)java.lang.UnsupportedOperationException 顺带提一嘴

public static void main(String[] args) {List<String> list= Arrays.asList("Sunday","Monday","TuesDay","WednesDay","ThursDay","Friday","Saturday");list.forEach(d->{System.out.println("value="+d);if (d.equals("ThursDay")){list.add("other");}});}
public static void main(String[] args) {List<String> list= Arrays.asList("Sunday","Monday","TuesDay","WednesDay","ThursDay","Friday","Saturday");list.stream().forEach(d->{System.out.println("value="+d);if (d.equals("ThursDay")){list.add("other");}});}

结果均是一样的

value=Sunday
value=Monday
value=TuesDay
value=WednesDay
value=ThursDay
Exception in thread "main" java.lang.UnsupportedOperationExceptionat java.util.AbstractList.add(AbstractList.java:148)at java.util.AbstractList.add(AbstractList.java:108)at com.meta.image.user.service.impl.AchievementServiceImpl.lambda$main$10(AchievementServiceImpl.java:1154)at java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948)at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:647)at com.meta.image.user.service.impl.AchievementServiceImpl.main(AchievementServiceImpl.java:1151)

参考链接:java.lang.UnsupportedOperationException错误的根源

2)add/remove操作

① list.forEach的增删结果

public static void main(String[] args) {List<String> list= new ArrayList<>();list.add("Sunday");list.add("Monday");list.add("Tuesday");list.add("Wednesday");list.add("Thursday");list.add("Friday");list.add("Saturday");list.forEach(d->{System.out.println("value="+d);if (d.equals("Thursday")){list.add("other");}});}
public static void main(String[] args) {List<String> list= new ArrayList<>();list.add("Sunday");list.add("Monday");list.add("Tuesday");list.add("Wednesday");list.add("Thursday");list.add("Friday");list.add("Saturday");list.forEach(d->{System.out.println("value="+d);if (d.equals("Thursday")){list.remove(d);}});}

list.forEach的add和remove执行结果均报错:

value=Sunday
value=Monday
value=Tuesday
value=Wednesday
value=Thursday
Exception in thread "main" java.util.ConcurrentModificationExceptionat java.util.ArrayList.forEach(ArrayList.java:1262)at com.meta.image.user.service.impl.AchievementServiceImpl.main(AchievementServiceImpl.java:1158)

② stream.forEach的增删结果

public static void main(String[] args) {List<String> list= new ArrayList<>();list.add("Sunday");list.add("Monday");list.add("Tuesday");list.add("Wednesday");list.add("Thursday");list.add("Friday");list.add("Saturday");list.stream().forEach(d->{System.out.println("value="+d);if (d.equals("Thursday")){list.remove(d);}});}

remove报错:

value=Sunday
value=Monday
value=Tuesday
value=Wednesday
value=Thursday
value=Saturday
value=null
Exception in thread "main" java.lang.NullPointerExceptionat com.meta.image.user.service.impl.AchievementServiceImpl.lambda$main$10(AchievementServiceImpl.java:1160)at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1384)at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:647)at com.meta.image.user.service.impl.AchievementServiceImpl.main(AchievementServiceImpl.java:1158)
public static void main(String[] args) {List<String> list= new ArrayList<>();list.add("Sunday");list.add("Monday");list.add("Tuesday");list.add("Wednesday");list.add("Thursday");list.add("Friday");list.add("Saturday");list.stream().forEach(d->{System.out.println("value="+d);if (d.equals("Thursday")){list.add(d);}});}

add报错:

value=Sunday
value=Monday
value=Tuesday
value=Wednesday
value=Thursday
value=Friday
value=Saturday
Exception in thread "main" java.util.ConcurrentModificationExceptionat java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1390)at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:647)at com.meta.image.user.service.impl.AchievementServiceImpl.main(AchievementServiceImpl.java:1158)

③结果及其补救办法

报错结果可以发现 stream.forEach的remove操作是会迭代整个列表的,纵然输出结果在前,但是依旧输出了null,空指针异常了。
参考我的另一篇博客:ArrayList 循环Remove遇到的坑

所以在应用时间过程中,当真的需要对集合进行add或者remove操作的时候,切记要懂得其结果是什么。

六、 总结

程序中若是最简单的赋值操作,那么list.forEach则满足需求;若需要对list做某些处理,比如筛选,则直接用stream.forEach,何时用parallelStream呢?详情下文源码说明。

关键字:详谈 Java中的list.forEach()和list.stream().forEach() 异同点

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: