如何将Java8流的元素添加到现有列表中

如何将Java8流的元素添加到现有列表中,java,java-8,java-stream,collectors,Java,Java 8,Java Stream,Collectors,显示如何将流的元素收集到新列表中。是否存在将结果添加到现有ArrayList中的一行程序?您只需将原始列表引用为收集器.toList()返回的列表即可 下面是一个演示: 导入java.util.array; 导入java.util.List; 导入java.util.stream.collector; 公开课参考{ 公共静态void main(字符串[]args){ List=Arrays.asList(1,2,3,4,5); 系统输出打印项次(列表); //只需收集偶数,并开始引用新列表作为原

显示如何将流的元素收集到新列表中。是否存在将结果添加到现有ArrayList中的一行程序?

您只需将原始列表引用为
收集器.toList()返回的列表即可

下面是一个演示:

导入java.util.array;
导入java.util.List;
导入java.util.stream.collector;
公开课参考{
公共静态void main(字符串[]args){
List=Arrays.asList(1,2,3,4,5);
系统输出打印项次(列表);
//只需收集偶数,并开始引用新列表作为原始列表。
list=list.stream()
.filter(n->n%2==0)
.collect(Collectors.toList());
系统输出打印项次(列表);
}
}
下面介绍了如何在一行中将新创建的元素添加到原始列表中

List=。。。;
//再次将列表中的偶数添加到列表中。
list.addAll(list.stream()
.filter(n->n%2==0)
.collect(收集器.toList())
);

这就是这个函数式编程范例所提供的。

简单的答案是否定的(或者应该是否定的)编辑:是的,这是可能的(见下面亚西尔亚斯的答案),但请继续阅读EDIT2:但请参阅斯图尔特·马克斯的答案,了解您仍然不应该这样做的另一个原因

较长的答案:

Java8中这些构造的目的是向语言引入一些概念;在函数式编程中,通常不修改数据结构,而是通过变换(如映射、过滤、折叠/减少等)在旧结构的基础上创建新结构

如果必须修改旧列表,只需将映射项收集到新列表中:

final List<Integer> newList = list.stream()
                                  .filter(n -> n % 2 == 0)
                                  .collect(Collectors.toList());
final List newList=List.stream()
.filter(n->n%2==0)
.collect(Collectors.toList());
然后再执行
list.addAll(newList)
——如果你真的必须这样做的话

(或者构建一个新列表,将旧列表和新列表连接起来,并将其分配回
list
变量这比
addAll
更符合FP的精神)

至于API:即使API允许这样做(同样,请参见assylias的回答),您也应该尽量避免这样做,至少在一般情况下是这样。最好不要与范式(FP)抗争,而是尝试学习它,而不是与之抗争(即使Java通常不是FP语言),并且只有在绝对需要时才诉诸“更脏”的策略

非常长的答案:(即,如果您按照建议实际查找和阅读FP简介/书籍)

要了解为什么修改现有列表通常是一个坏主意,并且会导致可维护性较差的代码,除非您正在修改局部变量,并且您的算法很短和/或很琐碎,这超出了代码可维护性问题的范围,请找一个函数式编程的好介绍(有数百个)然后开始阅读。“预览”的解释可能是这样的:它在数学上更合理,更容易推理不修改数据(在程序的大多数部分),并导致更高的层次和更少的技术性(以及更人性化,一旦你的大脑从老式的命令式思维转变过来)程序逻辑的定义。

已经给出了很好的理由,说明为什么您很可能不希望将流的元素收集到现有列表中

无论如何,如果您真的需要这个功能,您可以使用下面的一行程序

但正如他在回答中所解释的,如果这些流可能是平行流,你应该永远不要这样做-使用风险由你自己承担

list.stream().collect(Collectors.toCollection(() -> myExistingList));

就我所见,到目前为止,所有其他答案都使用收集器向现有流添加元素。然而,有一个较短的解决方案,它适用于顺序流和并行流。您可以简单地将方法forEachOrdered与方法引用结合使用

List<String> source = ...;
List<Integer> target = ...;

source.stream()
      .map(String::length)
      .forEachOrdered(target::add);
列出源代码=。。。;
列出目标=。。。;
source.stream()
.map(字符串::长度)
.forEachOrdered(目标::添加);
唯一的限制是,源和目标是不同的列表,因为只要流被处理,就不允许更改流的源

请注意,此解决方案适用于顺序流和并行流。但是,它不能从并发中获益。传递给forEachOrdered的方法引用将始终按顺序执行。

注意:显示如何使用
forEachOrdered()
添加到现有集合。这是一种对现有集合进行变异的有用且有效的技术。我的回答说明了为什么不应该使用
收集器
对现有集合进行变异

简短的回答是,至少在一般情况下,您不应该使用
收集器
来修改现有的集合

原因是收集器被设计为支持并行性,即使在不支持线程安全的集合上也是如此。他们这样做的方式是让每个线程在自己的中间结果集合上独立运行。每个线程获取自己的集合的方式是调用
收集器.supplier()
,每次都需要它返回一个新的集合

然后,这些中间结果的集合再次以线程限制的方式合并,直到有一个结果集合为止。这是
collect()
操作的最终结果

来自和的一些回答建议使用
Collectors.toCollection()
,然后传递一个返回现有列表而不是新列表的供应商。这违反了供应商的要求,即供应商每次返回一个新的空集合
List<String> destList = new ArrayList<>(Arrays.asList("foo"));
List<String> newList = Arrays.asList("0", "1", "2", "3", "4", "5");
newList.parallelStream()
       .collect(Collectors.toCollection(() -> destList));
System.out.println(destList);
List<String> destList =
    Collections.synchronizedList(new ArrayList<>(Arrays.asList("foo")));
[foo, 0, 1, 2, 3]
[foo, 2, 3, foo, 2, 3, 1, 0, foo, 2, 3, foo, 2, 3, 1, 0, foo, 2, 3, foo, 2, 3, 1, 0, foo, 2, 3, foo, 2, 3, 1, 0]
stream.collect(Collectors.toCollection(() -> existingList))
stream.sequential().collect(Collectors.toCollection(() -> existingList))
List<String> destList = Arrays.asList("foo");
List<String> newList = Arrays.asList("0", "1", "2", "3", "4", "5");

destList = Stream.concat(destList.stream(), newList.stream()).parallel()
            .collect(Collectors.toList());
System.out.println(destList);

//output: [foo, 0, 1, 2, 3, 4, 5]
import java.util.*;
import java.util.stream.Collectors;

public class AddingArray {

    public void addArrayInList(){
        List<Integer> list = Arrays.asList(3, 7, 9);

   // And we have an array of Integer type 

        int nums[] = {4, 6, 7};

   //Now lets add them all in list
   // converting array to a list through stream and adding that list to previous list
        list.addAll(Arrays.stream(nums).map(num -> 
                                       num).boxed().collect(Collectors.toList()));
     }
}