当前位置: 首页 > 知识库问答 >
问题:

为什么过滤流比简单返回子列表的迭代代码更快?

东郭海阳
2023-03-14
public static final int N = 50000000;

static List<Integer> sourceList = new ArrayList<>();

static {
  for (int i = 0; i < N; i++) {
    sourceList.add(i);
  }
}

@Benchmark
public List<Pair<Integer, Integer>> vanilla() {
   List<Pair<Integer, Integer>> collect1 = 
   sourceList.stream()
     .map(integer -> Pair.of(integer, integer))
     .collect(Collectors.toList());
   return collect1.subList(1000, 100000);
}

@Benchmark
public List<Pair<Integer, Integer>> stream() {
  return sourceList.stream()
    .map(value -> Pair.of(value, value))
    .filter(value -> value.getLeft() > 1000 && value.getLeft() < 100000)
    .collect(Collectors.toList());
}

Benchmark     Mode  Cnt    Score   Error  Units
Test.stream   avgt   20    9.867 ± 0.218  ns/op
Test.vanilla  avgt   20  183.304 ± 8.550  ns/op

共有1个答案

顾宏朗
2023-03-14

很可能是因为第一个元素必须填充50000000个元素的整个列表,这涉及到分配更多的内存,每次达到容量时都要复制列表使用的内部数组。

第二个只需要创建99000个元素的列表,因此分配的内存更少,内部数组的副本也更少。

一个更快的解决方案是在映射之前进行过滤,从而避免无用的装箱和创建对。当然,限制到10万也会更快。

 类似资料:
  • 我可以看到返回。但是现在已经添加到C++20标准中,为什么返回?cppreference指定: 返回值 等于last的迭代器。 这个选择背后的理性是什么? 与相比,用例的优势是什么?

  • 我正在阅读有效的java,有一个问题。我不理解为什么流迭代器返回Iterable。据我所知,Iterable包含迭代器接口。但在流api中,即使迭代器没有继承Iterable,这段代码仍在工作。 我对这些代码很困惑。因为迭代器和Iterable之间没有关系,除了Iterable有迭代器。

  • 我正在玩弄timeit,并注意到对一个小字符串进行简单的列表理解比对小的单个字符串列表进行相同的操作花费更长的时间。有什么解释吗?这几乎是时间的 1.35 倍。 在较低级别上发生了什么导致这种情况?

  • 我一直在玩Java 8 ,我决定对 和 流进行微基准测试。正如预期的那样, 的速度是原来的两倍,但还是出现了其他一些问题--如果我在将数据传递给 之前先对其进行排序,则与传递未排序列表相比, Map->Collect/code>得到结果所需的时间要多出5-8倍。 下面是一个更好的基准测试代码 结果也是相似的: 那么,我的问题是为什么过滤一个未排序的列表比过滤一个已排序的列表更快呢?

  • 下面的代码抛出,但我不明白为什么,该对象不是null。

  • 我试图以正确的顺序返回一个迭代器来处理单链表中的元素,但我无法使其正确工作。有没有一个简单的方法来完成这件事,因为我想我想得太多了。顺便说一下,这是在Java,我已经导入了迭代器包。