Java:遍历集合(这里是ArrayList)的最佳方法

110
今天我一直很开心地编码,当我遇到一段我已经使用过数百次的代码时:
通过Collection(这里是ArrayList)进行迭代
出于某种原因,我实际上查看了Eclipse的自动完成选项,这让我想知道:
以下循环比其他循环更好用的情况有哪些?
经典的数组索引循环:
for (int i = 0; i < collection.length; i++) {
  type array_element = collection.get(index);
}

Iterator的hasNext()/next():

for (Iterator iterator = collection.iterator(); iterator.hasNext();) {
  type type = (type) iterator.next();   
}

我最喜欢的原因是因为它很容易编写:

for (iterable_type iterable_element : collection) {

}

2
就我而言,我大多使用第三个循环。 - Harry Joy
2
第二种方法最好使用:for (Iterator iterator = collection.iterator(); iterator.hasNext();) { type type = iterator.next(); } - mike jones
4
集合接口不包含“get”方法,因此第一种方法并非总是可行的。 - ThePerson
在第一个选项中,对于“for循环”,应将collection.length更改为collection.size()。 - Vishwathma
6个回答

113

第一种方法非常有用,当你需要元素的索引时。对于 ArrayList,这基本上相当于另外两个变体,但如果使用 LinkedList,它将非常慢。

第二种方法在你不需要元素的索引但可能需要在迭代时删除元素时非常有用。但是,我认为它有一个缺点就是有些冗长。

第三种版本也是我的首选。它简短,并适用于所有情况,即您不需要任何索引或基础迭代器(即只访问元素,不删除它们或以任何方式修改 Collection - 这是最常见的情况)。


4
抢我说的话了,我本来也要提到LinkedList(并不是所有的“Collection”都可以通过索引轻松检索)。 - The Scrum Meister
只要需要循环元素,就最好使用第三个版本,因为所有不同的集合都已经存在实现,Sun或任何JDK实现都会努力提高性能,而不是每个人都去实现。 - Phani
@Phani:另外两个变体在任何JDK实现上也可以工作。 - MAK
我并不是说那些方法行不通,但是如果对于集合的实现有任何改进或性能变化,那么这些改进会自动应用于你的代码中,你就不需要手动写以提高性能。这是我的意思。 - Phani
1
据我所知,第三种形式仅仅是第二种形式的语法糖(即在幕后,foreach变体实际上使用了迭代器)。因此,任何性能优势都应该适用于两种变体。当然,第一种版本不会获得任何性能优势(例如,如果List被实现为树,则实际上会更慢)。 - MAK

39

它们都有各自的用途:

  1. 如果您有一个可迭代对象并需要无条件地遍历所有对象:

    for (iterable_type iterable_element : collection)

  2. 如果您有一个可迭代对象,但需要有条件地遍历:

    for (Iterator iterator = collection.iterator(); iterator.hasNext();)

  3. 如果数据结构没有实现迭代器:

    for (int i = 0; i < collection.length; i++)


你能按条件遍历第一个方法吗:if (iterable_element.some_attribute) { // do something; } else { // do nothing; }。如果可以,那么第一种和第二种方法基本上没有区别,除了语法糖。 - Thomas Nguyen
1 可以使用 break 和/或 continue 条件性地遍历,就像其他的一样。 - arcyqwerty

16

Java 8还有一个名为 collections’ stream() 的实用程序

collection.forEach((temp) -> {
            System.out.println(temp);
});
或者
collection.forEach(System.out::println);

关于Java 8的流和集合的更多信息,供好奇者参考链接


4

它们之间没有一个比另一个更好。对我来说,第三个更易读,但对于不使用foreach的人来说,它可能看起来很奇怪(他们可能更喜欢第一个)。所有3种方式对理解Java的人来说都很清晰,因此选择使您对代码感觉更好的那个。

第一个是最基本的,因此它是最通用的模式(适用于数组,我能想到的所有可迭代对象)。这是我能想到的唯一区别。在更复杂的情况下(例如,您需要访问当前索引,或者需要过滤列表),分别使用第一种和第二种情况可能更有意义。对于简单的情况(可迭代对象,没有特殊要求),第三种方法似乎最简洁。


2
第一种选择在性能方面更好(因为ArrayList实现了RandomAccess接口)。根据Java文档,如果对于该类的典型实例,以下循环:
 for (int i=0, n=list.size(); i < n; i++)
     list.get(i);

比这个循环运行得更快:
 for (Iterator i=list.iterator(); i.hasNext(); )
     i.next();

希望这能有所帮助。 第一种选择对于顺序访问列表来说速度较慢。


2

这里有一个例子

Query query = em.createQuery("from Student");
             java.util.List list = query.getResultList();
             for (int i = 0; i < list.size(); i++) 
             {

                 student = (Student) list.get(i);
                 System.out.println(student.id  + "  " + student.age + " " + student.name + " " + student.prenom);

             }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接