Java:遍历Collection的最佳方法(此处为ArrayList)


98

今天,当我获得一段已经使用了数百次的代码时,我很高兴地开始编码:

遍历一个Collection(这里是ArrayList)

由于某种原因,我实际上查看了Eclipse的自动完成选项,这让我感到奇怪:

在哪些情况下,以下循环比其他情况更好使用?

经典的数组索引循环:

for (int i = 0; i < collection.length; i++) {
  type array_element = collection.get(index);
}

迭代器具有next()/ next():

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

我最喜欢的是因为它写起来很简单:

for (iterable_type iterable_element : collection) {

}

2
说到我,我主要使用3rd循环。
哈里·乔伊

1
第二种方法最好使用:for (Iterator<type> iterator = collection.iterator(); iterator.hasNext();) { type type = iterator.next(); }
迈克·琼斯

4
集合接口不包含方法“ get”,因此第一个方法并非总是可行的。
ThePerson

Answers:


104

当您还需要元素的索引时,第一个很有用。这基本上与ArrayLists 的其他两个变体等效,但是如果使用,则速度会非常慢LinkedList

当您不需要元素的索引但可能需要在迭代时删除元素时,第二个元素很有用。但是,这样做的缺点是IMO过于冗长。

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


3
+1击败我。会提到LinkedList(并非所有 Collection索引都便宜)。
Scrum Meister

只要需要循环元素,最好使用第3版,因为对于所有不同的Collections,Sun都已经存在实现,或者任何JDK实现都在努力提高性能,而不是每一个都提高。
帕尼

@Phani:其他两个变体也可以在任何JDK实现上使用。
MAK

我并不是说这些是行不通的,但是如果有可能对集合的实现进行了某些改进或性能更改,那么它将自动适用于您的代码,您无需编写即可提高性能是我的意思
Phani

1
@Phani:AFAIK第三种形式只是第二种形式的语法糖(即,在幕后的foreach变体实际上使用了迭代器)。因此,两种变体都应具有任何性能优势。当然,第一个版本不会获得任何性能上的好处(例如,如果将List其实现为树,则实际上会更慢)。
MAK

36

它们都有自己的用途:

  1. 如果您有遍历并且需要无条件遍历所有这些遍:

    用于(iterable_type iterable_element:集合)

  2. 如果您有迭代路线,但需要有条件遍历:

    for(迭代器iterator = collection.iterator(); iterator.hasNext();)

  3. 如果数据结构未实现可迭代:

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


您可以这样做来有条件地遍历第一个方法吗:if(iterable_element.some_attribute){//做点什么;} else {//不执行任何操作;}。如果是,那么除了语法糖之外,第一种方法和第二种方法之间基本上没有区别。
Thomas Nguyen 2015年

1 break和其他使用和/或continue
arcyqwerty

13

Java 8还具有集合的stream()util

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

要么

collection.forEach(System.out::println);

有关Java 8流和奇迹收集器的更多信息,请链接


4

他们中没有一个比其他人“更好”。对我来说,第三个是更具可读性的,但是对于不使用foreach的人来说,它可能看起来很奇怪(他们可能更喜欢第一个)。所有这三者对理解Java的人来说都很清楚,因此请选择使您对代码感觉更好的任何一种。

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


2

第一个选择是更好的性能(因为ArrayList实现RandomAccess接口)。根据java doc,如果对于类的典型实例,此循环是,List实现应实现RandomAccess接口:

 for (int i=0, n=list.size(); i < n; i++)
     list.get(i);

比这个循环运行得更快:

 for (Iterator i=list.iterator(); i.hasNext(); )
     i.next();

希望对您有所帮助。对于顺序访问列表,第一种选择将很慢。


1

这是一个例子

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);

             }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.