我有一个包含一个元素的列表,但以后可能会有更多。我使用的列表是一个 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
. 这可能是减速的原因。一些实现对Iterator
or有复杂的实现ListIterator
。
那么答案就是风格和可读性的问题。大多数 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 的迭代器代码,它非常简单,唯一真正的额外开销来自对象创建和并发修改检查。
For LinkedList, however, this type of loop would give horrible performance as the .get() method on LinkedList is O(n), and an Iterator would be much faster, since it's simply doing a pointer check and reassignment for each iteration which makes it O(1) for each call to next().