Java中连接两个列表项的最快方法

时间:2021-06-18 08:29:22

标签: java java-stream

我想分别加入两个列表的项目。

这是我的代码:

1.

List<String> pairs = list1.stream()
                          .parallel()
                          .flatMap(item1 -> list2.stream()
                                                 .parallel()
                                                 .map(item2 -> item1 + " " + item2))
                          .collect(Collectors.toList());

当我尝试类似的方法时,上面的方法是最快的..但我觉得这个方法不是并行的。 (因为结果的顺序总是一样的..!)

有没有更快的方法?最终结果列表的顺序无关紧要。

谢谢!

========================================

我尝试了另外两种方法

2.

List<String> pairs = new ArrayList<>();
    for(String item1 : list1)
        for(String item2 : list2)
            pairs.add(item1 + " " + item2);
    pool.submit(() -> {
        List<String> pairs = list1.stream()
                  .parallel()
                  .flatMap(item1 -> list2.stream()
                                         .parallel()
                                         .map(item2 -> item1 + " " + item2))
                  .collect(Collectors.toList());
    }).get();

2 个答案:

答案 0 :(得分:1)

获取顺序流的问题在 flatMap 中。 这是关于 efficiently splittable streams 的文章。

有几种方法可以分别组合两个或多个流。其中一种方法是使用 Guava Streams:

Streams
  .zip(list1.stream(), list2.stream(), (item1, item2) -> item1 + ":" + item2)

请注意,此 Stream 也不是 efficiently splittable。所以它会损害并行性能。您可以在此处找到更多方法:

Zipping Collections in Java

答案 1 :(得分:0)

<块引用>

但是我感觉这个方法不是并行的。 (因为结果的顺序总是一样的..!)

你这里的推理是错误的。 toList() 可以在并行处理后按顺序返回项目。来自the docs

<块引用>

如果流具有遇到顺序,但用户并不特别关心该遇到顺序,则使用 unordered() 显式取消流的排序可能会提高某些有状态或终端操作的并行性能。然而,大多数流管道,例如上面的“块权重总和”示例,即使在排序约束下仍然有效地并行化。

有关其工作原理的更多详细信息,我们可以查看 Collectors.toList 的实现:

    public static <T>
    Collector<T, ?, List<T>> toList() {
        return new CollectorImpl<>(ArrayList::new, List::add,
                                   (left, right) -> { left.addAll(right); return left; },
                                   CH_ID);
    }

处理流的每个线程创建一个单独的ArrayList,并用add按顺序将处理过的元素添加到列表中。稍后这些单独的列表使用 addAll 合并。由于每个线程处理一个有序批次的项目,而合并过程保留了批次的顺序,因此保留了整体顺序。

相关问题