Collector的Javadoc演示了如何将流中的元素收集到一个新的List中。是否有一行程序将结果添加到现有的数组列表中?


当前回答

Erik Kaplun已经给出了很好的理由,为什么您不希望将流的元素收集到现有的List中。

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

但正如在其他答案中指出的那样,你永远不应该这样做,特别是如果流可能是并行流——使用风险自负……

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

其他回答

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

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

source.stream()
      .map(String::length)
      .forEachOrdered(target::add);

唯一的限制是,源和目标是不同的列表,因为只要流正在处理,您就不允许对流的源进行更改。

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

我将连接旧列表和新列表作为流,并将结果保存到目标列表。并行也能很好地工作。

我将使用Stuart Marks给出的一个公认答案的例子:

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]

希望能有所帮助。

Erik Kaplun已经给出了很好的理由,为什么您不希望将流的元素收集到现有的List中。

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

但正如在其他答案中指出的那样,你永远不应该这样做,特别是如果流可能是并行流——使用风险自负……

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

简短的回答是没有(或者应该是没有)。编辑:是的,这是可能的(见下面assylias的答案),但继续读下去。编辑2:但是看看斯图尔特·马克斯的回答,你仍然不应该这样做的另一个原因!

更长的答案是:

Java 8中这些构造的目的是将函数式编程的一些概念引入该语言;在函数式编程中,数据结构通常不会被修改,相反,通过映射、过滤、折叠/缩减和许多其他转换,可以从旧的数据结构中创建新的数据结构。

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

final List<Integer> newList = list.stream()
                                  .filter(n -> n % 2 == 0)
                                  .collect(Collectors.toList());

然后执行list.addAll(newList) -如果你真的必须这样做。

(或者构造一个连接新旧列表的新列表,并将其赋值给list变量——这比addAll更符合FP的精神)

至于API:即使API允许这样做(再次,参见assylias的回答),你应该尽量避免这样做,至少在一般情况下。最好不要对抗范式(FP),而是尝试学习它,而不是对抗它(尽管Java通常不是FP语言),只有在绝对需要时才采用“更肮脏”的策略。

很长的答案:(也就是说,如果你把寻找和阅读FP介绍/书籍的努力包括在内的话)

To find out why modifying existing lists is in general a bad idea and leads to less maintainable code—unless you're modifying a local variable and your algorithm is short and/or trivial, which is out of the scope of the question of code maintainability—find a good introduction to Functional Programming (there are hundreds) and start reading. A "preview" explanation would be something like: it's more mathematically sound and easier to reason about to not modify data (in most parts of your program) and leads to higher level and less technical (as well as more human friendly, once your brain transitions away from the old-style imperative thinking) definitions of program logic.

您只需要将您的原始列表引用为collections . tolist()返回的列表。

下面是一个演示:

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Reference {

  public static void main(String[] args) {
    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
    System.out.println(list);

    // Just collect even numbers and start referring the new list as the original one.
    list = list.stream()
               .filter(n -> n % 2 == 0)
               .collect(Collectors.toList());
    System.out.println(list);
  }
}

下面是如何在一行中将新创建的元素添加到原始列表。

List<Integer> list = ...;
// add even numbers from the list to the list again.
list.addAll(list.stream()
                .filter(n -> n % 2 == 0)
                .collect(Collectors.toList())
);

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