只需在列表下面进行迭代并通过Java 8流添加到另一个共享的可变列表中即可。
List<String> list1 = Arrays.asList("A1","A2","A3","A4","A5","A6","A7","A8","B1","B2","B3");
List<String> list2 = new ArrayList<>();
Consumer<String> c = t -> list2.add(t.startsWith("A") ? t : "EMPTY");
list1.stream().forEach(c);
list1.parallelStream().forEach(c);
list1.forEach(c);
以上三个迭代之间有什么区别,我们需要使用哪一个。有什么考虑吗?
答案 0 :(得分:4)
无论您使用并行Stream
还是顺序forEach
,当目标是生成List
时都不应使用map
。将collect
与List<String> list2 =
list2.stream()
.map(item -> item.startsWith("A") ? item : "EMPTY")
.collect(Collectors.toList());
一起使用:
var_dump()
答案 1 :(得分:3)
从功能上讲,对于简单案例,它们几乎是相同的,但总的来说,存在一些隐藏的差异:
forEach
的Javadoc开始,列举可重复的用例,说明:对Iterable的每个元素执行给定的动作,直到所有 元素已处理或操作引发异常。
我们还可以遍历一个集合并在每个元素上执行给定的操作-只需传递一个实现Consumer接口的类
void forEach(Consumer<? super T> action)
Stream.forEach
的顺序是随机的,而Iterable.forEach
总是按照Iterable
的迭代顺序执行。Iterable.forEach
正在遍历同步的集合,则Iterable.forEach
会获取一次该集合的锁,并将其保存在对action方法的所有调用中。 Stream.forEach调用使用集合的分隔符,该分隔符不会锁定Stream.forEach
中指定的操作必须是不干扰,而允许Iterable.forEach
在基础ArrayList
中设置值没有问题。ConcurrentModificationException.
https://docs.oracle.com/javase/8/docs/api/java/util/ArrayList.html#fail-fast
更多信息:
答案 2 :(得分:0)
我个人认为,在使用流时,应该以一种方式编写代码,如果切换到并行流,则不会破坏代码(产生错误的结果)。 想象一下,如果在代码中您正在同一共享内存(列表2)上进行读写,并且将进程分布到多个线程中(使用并行流)。那你就是DOOMED。因此,您有几种选择。
使共享内存(list2)线程安全。例如使用AtomicReferences
List<String> list2 = new ArrayList<>();
AtomicReference<List<String>> listSafe = new AtomicReference<>();
listSafe.getAndUpdate(strings -> {strings.add("newvalue"); return strings;});
或者您可以使用纯功能方法(无副作用的代码) 就像@Eran解决方案一样。