for-each vs for vs while

我想知道在ArrayList或各种List上实现“for-each”循环的最佳方法是什么。

以下哪项实施最好,为什么? 或者有最好的方法吗?

感谢您的帮助。

List values = new ArrayList(); values.add("one"); values.add("two"); values.add("three"); ... //#0 
for(String value : values) { ... } //#1
for(int i = 0; i < values.size(); i++) { String value = values.get(i); ... } //#2
for(Iterator it = values.iterator(); it.hasNext(); ) { String value = it.next(); ... } //#3
Iterator it = values.iterator(); while (it.hasNext()) { String value = (String) it.next(); ... }

List values = new ArrayList(); values.add("one"); values.add("two"); values.add("three"); ... //#0
for(String value : values) { ... } //#1
for(int i = 0; i < values.size(); i++) { String value = values.get(i); ... } //#2
for(Iterator it = values.iterator(); it.hasNext(); ) { String value = it.next(); ... } //#3
Iterator it = values.iterator(); while (it.hasNext()) { String value = (String) it.next(); ... }

List values = new ArrayList(); values.add("one"); values.add("two"); values.add("three"); ... //#0
for(String value : values) { ... } //#1
for(int i = 0; i < values.size(); i++) { String value = values.get(i); ... } //#2
for(Iterator it = values.iterator(); it.hasNext(); ) { String value = it.next(); ... } //#3
Iterator it = values.iterator(); while (it.hasNext()) { String value = (String) it.next(); ... }

List values = new ArrayList(); values.add("one"); values.add("two"); values.add("three"); ... //#0
for(String value : values) { ... } //#1
for(int i = 0; i < values.size(); i++) { String value = values.get(i); ... } //#2
for(Iterator it = values.iterator(); it.hasNext(); ) { String value = it.next(); ... } //#3
Iterator it = values.iterator(); while (it.hasNext()) { String value = (String) it.next(); ... }

List values = new ArrayList(); values.add("one"); values.add("two"); values.add("three"); ... //#0
for(String value : values) { ... } //#1
for(int i = 0; i < values.size(); i++) { String value = values.get(i); ... } //#2
for(Iterator it = values.iterator(); it.hasNext(); ) { String value = it.next(); ... } //#3
Iterator it = values.iterator(); while (it.hasNext()) { String value = (String) it.next(); ... }

List values = new ArrayList(); values.add("one"); values.add("two"); values.add("three"); ... //#0
for(String value : values) { ... } //#1
for(int i = 0; i < values.size(); i++) { String value = values.get(i); ... } //#2
for(Iterator it = values.iterator(); it.hasNext(); ) { String value = it.next(); ... } //#3
Iterator it = values.iterator(); while (it.hasNext()) { String value = (String) it.next(); ... }

#3有一个缺点,因为迭代器的范围超出了循环的末尾。 其他解决方案没有这个问题。

#2与#0完全相同,除了#0更具可读性且不易出错。

#1(可能)效率较低,因为它每次通过循环调用.size()

#0通常是最好的,因为:

  • 它是最短的
  • 它最不容易出错
  • 它是惯用的,易于其他人一目了然
  • 它由编译器有效地实现
  • 它不会使用不必要的名称污染您的方法范围(在循环外)

简短的回答是使用版本0.在Android的文档中查看部分标题使用增强型循环语法以设计性能 。 该页面有很多好东西,非常简洁明了。

在我看来,#0是最容易阅读的,但#2和#3也同样适用。 这三者之间应该没有性能差异。

在几乎任何情况下你都不应该使用#1。 您在问题中说明您可能希望迭代“各种列表”。 如果您碰巧在LinkedList上进行迭代,则#1将是n ^ 2复杂度:不好。 即使您完全确定使用支持高效随机访问的列表(例如ArrayList ),通常也没有理由使用#1而不是其他任何一个。

回应OP的评论。

但是,更新时需要#1(如果不是仅仅改变当前项目或将结果构建为新列表),则附带索引。 由于在这种情况下List <>是一个ArrayList <>,因此get()(和size())是O(1),但对于所有List-contract类型,它们都不相同。

让我们看看这些问题:

对于List契约的所有实现, get(int)肯定不是O(1) 。 但是,对于java.util所有List实现,AFAIK, size()O(1) 。 但是你认为#1对于许多List实现来说并不是最理想的。 实际上,对于像LinkedList这样的列表,其中get(int)O(N) ,#1方法导致O(N^2)列表迭代。

ArrayList情况下,手动提升size()的调用,将其分配给(最终)局部变量是一件简单的事情。 通过这种优化,#1代码明显快于其他情况…对于ArrayList

您在迭代元素时更改列表的观点引发了许多问题:

  • 如果使用显式或隐式使用迭代器的解决方案执行此操作,则根据列表类,您可能会获得ConcurrentModificationException 。 如果您使用其中一个并发集合类,则不会获得exception,但javadocs声明迭代器不一定会返回所有列表元素。

  • 如果你使用#1代码(按原样)执行此操作,则表示您遇到了问题。 如果修改是由同一个线程执行的,则需要调整索引变量以避免丢失条目,或者将它们返回两次。 即使你把所有事情都搞定了,在当前位置之前同时插入的列表条目也不会显示出来。

  • 如果#1情况下的修改是由不同的线程执行的,则很难正确同步。 核心问题是get(int)size()是单独的操作。 即使它们是单独同步的,也没有什么可以阻止其他线程在size和调用之间修改列表。

简而言之,迭代正在同时修改的列表是棘手的,应该避免…… 除非你真的知道你在做什么