在java中将for循环等价于List.get



我有一个包含一个元素的列表,但以后可能会有更多元素。我使用的列表是一个 ArrayList。我发现通过调用 List.get(0) 而不是使用 for 循环,我得到了更快的结果。这是为什么呢?循环 1 个项目不应该和获取 1 个项目相同吗?如果不是,那么我如何获得类似的性能?我知道我的数组最终会大于一个项目。我在 opengl 渲染器的主体中使用此循环。当我使用循环时,我的 fps 下降了 45。

编辑:我已经解决了这个问题。我的渲染器每次渲染时都会向列表中添加一个新值。

在 Java 中使用增强的 for 循环(for-each)会生成如下所示的编译代码:

Iterator<Thing> it = list.iterator();
while(it.hasNext()) {
  yourLoop.loopBody(it.next());
}

您可能期望它等同于此?

for (int i = 0; i < list.size(); i++) {
  yourLoop.loopBody(list.get(i));
}

但事实并非如此,构造迭代器需要您观察的额外时间。

不知道List实现,就无法真正给出具体的答案。例如,ArrayList由数组支持,因此调用get本质上是一种数组访问。

另一方面,使用 for 循环的"foreach"版本需要创建一个Iterator。这可能是减速的原因。某些实现具有IteratorListIterator的复杂实现。

那么答案就是风格和可读性的问题。大多数Java程序员会说foreach循环更具可读性,并且更清晰。并且通过一些List实现(例如 LinkedList)快得多。

我不是集合方面的专家,但设置迭代必须比简单地获取特定项目更昂贵。

通过设置 foreach,我们不知道集合中有多少项,因此无论列表有多少项,它都会将其设置为迭代。

一般来说,如果你担心速度,如果你知道你正在使用ArrayList,你最快的方法是:

int size = list.size();
for (int i=0;i<size;i++) {
  Thing thing = list.get(i);
}

虽然"size"方法的开销很小,但它仍然是不需要在每个循环中调用的开销。 ArrayList 上的 get() 方法是 O(1)。 这应该为迭代器提供类似的性能。 如果您查看 ArrayList 的迭代器代码,它非常简单,唯一真正的额外开销来自对象创建和并发修改检查。

然而,对于 LinkedList,这种类型的循环会给出可怕的性能,因为 LinkedList 上的 .get() 方法是 O(n),而迭代器会快得多,因为它只是对每次迭代进行指针检查和重新分配,这使得每次调用 next() 时都是 O(1)。

相关内容

  • 没有找到相关文章

最新更新