集合流到新集合

我正在寻找最无痛的方式来过滤收藏品。我想像这样的东西

Collection<?> foo = existingCollection.stream().filter( ... ). ...

但是我不确定如何从过滤器转换为返回或填充另一个集合是最好的。大多数例子看起来像“在这里你可以打印”。可能我漏掉了一个构造函数或者输出方法。

89468 次浏览

作为一个更符合 Java8函数式编程风格的例子:

Collection<String> a = Collections.emptyList();
List<String> result = a.stream().
filter(s -> s.length() > 0).
collect(Collectors.toList());

java.util.stream文档中的一个例子:

List<String>results =
stream.filter(s -> pattern.matcher(s).matches())
.collect(Collectors.toList());

Collectors有一个 toCollection()方法,我建议这样看。

大多数示例避免将结果存储到 Collection中是有原因的。这不是推荐的编程方式。您已经有了一个 Collection,提供源数据和集合的 Collection本身没有任何用处。您希望对其执行某些操作,因此理想的情况是使用流执行操作,并跳过在中间 Collection中存储数据。这是大多数例子试图暗示的。

当然,有很多现有的 API 可以与 Collection一起工作,而且将来也会一直存在。因此,Stream API 提供了不同的方法来处理对 Collection的需求。

  • 获取包含所有元素(JDK 16)的不可修改的 List实现:

    List<T> results = l.stream().filter(…).toList();
    
  • 获得一个任意的 List实现,其中包含结果:

    List<T> results = l.stream().filter(…).collect(Collectors.toList());
    
  • 获得一个像 List.of(…)(JDK 10)那样禁止 null无法修改的 List:

    List<T> results = l.stream().filter(…).collect(Collectors.toUnmodifiableList());
    
  • 获得一个任意的 Set实现,其中包含结果:

    Set<T> results = l.stream().filter(…).collect(Collectors.toSet());
    
  • 获取特定的 Collection:

    ArrayList<T> results =
    l.stream().filter(…).collect(Collectors.toCollection(ArrayList::new));
    
  • 添加到现有的 Collection:

    l.stream().filter(…).forEach(existing::add);
    
  • 创建一个数组:

    String[] array=l.stream().filter(…).toArray(String[]::new);
    
  • 使用数组创建具有特定行为(可变、固定大小)的列表:

    List<String> al=Arrays.asList(l.stream().filter(…).toArray(String[]::new));
    
  • 允许并行的有能力的流添加到临时的本地列表中,然后加入它们:

    List<T> results
    = l.stream().filter(…).collect(ArrayList::new, List::add, List::addAll);
    

    (注意: 这与 Collectors.toList()当前的实现方式密切相关,但这只是实现细节,也就是说,不能保证 toList()收集器的未来实现仍然返回 ArrayList)

您可能希望使用来自 Collectors类的 toListtoSettoMap方法。

然而,为了获得更多的控制权,可以使用 toCollection方法。下面是一个简单的例子:

Collection<String> c1 = new ArrayList<>();
c1.add("aa");
c1.add("ab");
c1.add("ca");


Collection<String> c2 = c1.stream().filter(s -> s.startsWith("a")).collect(Collectors.toCollection(ArrayList::new));


Collection<String> c3 = c1.stream().filter(s -> s.startsWith("a")).collect(Collectors.toList());


c2.forEach(System.out::println); // prints-> aa ab
c3.forEach(System.out::println); // prints-> aa ab