Java-8并行流(parallelStream(...))-> 填充ArrayList

5
我尝试了这段代码:
 final List<ScheduleContainer> scheduleContainers = new ArrayList<>();
 scheduleResponseContent.getSchedules().parallelStream().forEach(s -> scheduleContainers.addAll(s));

使用parallelStream时,由于scheduleContainers中的某些条目为空,我会得到ArrayIndexOutOfBoundException或NullpointerException。

使用... .stream()...时一切正常。 我的问题是是否有可能修复这个问题或者我误用了parallelStream?


你是如何使用parallelStream向列表中添加元素的?能否演示一下? - Surajit Biswas
2个回答

10

是的,你正在错误地使用parallelStream。首先,正如你在之前的问题中已经两次提到的那样,你应该默认使用stream()而不是parallelStream()。并行化通常会带来固有成本,使得事情比简单的顺序流更加低效,除非你有大量数据需要处理,并且每个元素的处理需要时间。在使用并行流之前,你应该先检查是否存在性能问题,并测量并行流是否可以解决它。同时,使用并行流出错的可能性也更大,正如你的帖子所展示的那样。

阅读当可能时,我是否应该总是使用并行流?以获取更多论据。

其次,这段代码根本不是线程安全的,因为它使用了几个并发线程来添加到一个线程不安全的ArrayList中。如果你使用collect()来创建最终列表,而不是forEach()并自己添加东西到列表中,则可以确保线程安全。

代码应该是

List<ScheduleContainer> scheduleContainers =
    scheduleResponseContent.getSchedules().
                           .stream()
                           .flatMap(s -> s.stream())
                           .collect(Collectors.toList());

你也可以使用 .toList() 替代 .collect(Collectors.toList()),这样仍然是线程安全的:List<ScheduleContainer> scheduleContainers = scheduleResponseContent.getSchedules().stream() .flatMap(s -> s.stream()).toList() - BugsOverflow

6

对于错误的原因不确定,但是有更好的方法使用Stream API来从多个输入列表创建一个列表。

final List<ScheduleContainer> scheduleContainers =
    scheduleResponseContent.getSchedules()
                           .parallelStream()
                           .flatMap(s->s.stream()) // assuming getSchedules() returns some 
                                                   // Collection<ScheduleContainer>, based 
                                                   // on your use of addAll(s)
                           .collect(Collectors.toList());

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接