Java 在遍历列表时,以下哪种方法最有效?

Java 在遍历列表时,以下哪种方法最有效?,java,performance,Java,Performance,2方法: for(int i = list.length - 1; i >= 0; i--) { System.out.println(list.get(i)); } 3方法: for(T t : list) { System.out.println(t); } Iterator it=list.Iterator(); while(it.hasNext()){ System.out.println(it.next()); } 效率不太可能显著-当然,System.out.pri

2方法:

for(int i = list.length - 1; i >= 0; i--) {
  System.out.println(list.get(i));
}
3方法:

for(T t : list) {
  System.out.println(t);
}
Iterator it=list.Iterator();
while(it.hasNext()){
System.out.println(it.next());
}

效率不太可能显著-当然,
System.out.println
更可能成为您特定示例中的瓶颈

然而,第二种方法(增强for循环)是可读性最强的。请注意,这三种方法做的事情并不相同——第一种方法将从末尾而不是开始迭代。获得正确的行为几乎总是胜过跑得稍微快一点。代码的可读性越高,就越有可能获得正确的代码

关注可读性,衡量应用程序的性能,如果出现问题,微观优化瓶颈(继续在每一步进行衡量)

编辑:我的回答是基于问题的第一行,显示了正在使用的
ArrayList

如果您想要任何
列表的答案,那么根本就没有准确的答案<代码>列表
不保证复杂性。它并没有说你应该期望
get
有多快,也没有说你应该期望迭代器有多快。您可以使用一个具有良好随机访问能力的实现,但迭代器速度非常慢。不太可能,但它仍然是一个有效的
列表

简言之:如果你关心效率,你需要知道你使用的是什么类型的列表。一般来说,迭代可能相当有效,而随机访问可能有效,也可能无效。(它可能比迭代更有效,但不太可能明显更有效。)在实践中,我的经验是,在大多数应用程序中,您实际上拥有足够的知识来做出合理的判断。。。但我通常还是先编写可读性代码


正如其他人所指出的,如果您确实希望使用随机访问来获取元素,那么确保您的列表也实现了接口是值得的。

我更喜欢方法2,除非您需要调用迭代器对象上的某个对象(如
iterator.remove()
),在这种情况下,我更喜欢方法3

我使用方法1的唯一情况是,如果我仍然需要跟踪循环中的索引(并且只有在
列表
的情况下,它是一个密集的类似数组的实现,比如
ArrayList

更新:
与评论/其他答案一样,我现在更喜欢在跟踪索引的列表中进行迭代时使用
ListIterator
。让方法1只对通过任何其他方法都无法实现的事情有用。

我发现比较可能有助于你向前推进

如果你有一个没有随机访问支持的长列表,第一种方法会慢得多。例如,在LinkedList上调用get(1000000)必须从列表的开头循环1000000个元素才能到达第1000000个元素。第二种和第三种方法应该是等效的


如果与您的情况相关,请列出提供对其元素的恒定时间随机访问的实现,这些实现应该包含java.util.RandomAccess标记接口。至少标准API中的列表实现是这样的。

许多因素都会影响度量

首先,请注意,您的第二个和第三个备选方案是字节码等效的。事实上,Java是一种语法糖,这意味着,在您的情况下,第二种选择在编译后将与第三种选择完全相同

最明显的是所选择的实现。如果您使用
LinkedList
而不是
ArrayList
进行此测试,您会发现迭代器显然比随机数组访问更快。你甚至会发现,在某些情况下,在
链接列表上迭代比在
数组列表上迭代要快。你现在怎么办?在大多数代码中,您将无理由地从一个插入到另一个插入

因此,作为一般的经验法则,为了可读性和代码效率,我倾向于使用第二种方法。

On
RandomAccess
工具。文件明确说明了这意味着什么:

列表
实现使用的标记接口,用于指示它们支持快速(通常为固定时间)随机访问。[…]根据经验,如果对于类的典型实例,此循环:

Iterator<T> it = list.iterator();     
while(it.hasNext()) {
  System.out.println(it.next());
}
for (int i=0, n=list.size(); i < n; i++)
     list.get(i);
因此,对于正确地
实现随机访问的
列表
,索引的-
get
更快

然而,请注意,对于
LinkedList
,上述代码表现出二次性能的情况并非如此。这是因为
LinkedList
不允许固定时间随机访问;也就是说,
get
对于
LinkedList
是线性的

请注意,即使索引-
get
更快,它也只会以一个常数因子执行。首先配置文件以查看此优化尝试是否值得

相关问题

对每个
vs
迭代器
循环启用

您应该关注的这两种结构的性能之间没有显著差异。每个
循环的
可读性要高得多,但适用于更有限的场景,因此在这些场景中您应该使用它们。如果每个循环的
不适用,则使用
迭代器
循环

引用《有效Java第二版》第46项:对于每个
循环,首选
,而对于
循环,首选传统的

发行版1.5中引入的
for each
循环消除了混乱 以及通过隐藏ite而产生错误的机会
for (int i=0, n=list.size(); i < n; i++)
     list.get(i);
for (Iterator i=list.iterator(); i.hasNext(); )
     i.next();
// The preferred idiom for iterating over collections and arrays
for (Element e : elements) {
    doSomething(e);
}
ListIterator<T> it = list.listIterator();
while (it.hasNext()) {
    T t = it.next;
    int index = it.previousIndex();
    System.out.printf("%d => %s%n", index, t);
}
for(int i = 0, n=list.size(); i < n; i++) {
  System.out.println(list.get(i));
}