对 Java 语言有点陌生,我试图让自己熟悉所有可能遍历列表(或可能是其他集合)的方式(或至少是非病态的方式)以及它们的优点或缺点每个。
给定一个 List<E> list
对象,我知道以下遍历所有元素的方法:
基本 for loop (当然,也有等效的 while
/do while
循环)
// Not recommended (see below)!
for (int i = 0; i < list.size(); i++) {
E element = list.get(i);
// 1 - can call methods of element
// 2 - can use 'i' to make index-based calls to methods of list
// ...
}
注意:正如@amarseillan 指出的那样,这种形式是一个糟糕的选择
用于迭代 List
s,因为实际执行
get
方法可能不如使用 Iterator
时有效.
例如,LinkedList
实现必须遍历所有
i 前面的元素得到第 i 个元素。
在上面的例子中,List
是不可能的。实现到
“保存它的位置”以使 future 的迭代更有效率。
对于 ArrayList
这并不重要,因为 get
的复杂性/成本是常数时间 (O(1)) 而对于 LinkedList
它是否与列表的大小成正比(O(n))。
有关内置的计算复杂性的更多信息Collections
实现,请查看 this question .
增强 for loop (很好解释 in this question )
for (E element : list) {
// 1 - can call methods of element
// ...
}
Iterator
for (Iterator<E> iter = list.iterator(); iter.hasNext(); ) {
E element = iter.next();
// 1 - can call methods of element
// 2 - can use iter.remove() to remove the current element from the list
// ...
}
ListIterator
for (ListIterator<E> iter = list.listIterator(); iter.hasNext(); ) {
E element = iter.next();
// 1 - can call methods of element
// 2 - can use iter.remove() to remove the current element from the list
// 3 - can use iter.add(...) to insert a new element into the list
// between element and iter->next()
// 4 - can use iter.set(...) to replace the current element
// ...
}
Functional Java
list.stream().map(e -> e + 1); // Can apply a transformation function for e
Iterable.forEach , Stream.forEach , ...
(来自 Java 8 的 Stream API 的 map 方法(请参阅@i_am_zero 的答案)。)
在实现 Iterable
的 Java 8 集合类中(例如,所有 List
s)现在都有一个 forEach
方法,可以用来代替 for loop statement如上所示。 (这里是 another question,提供了很好的比较。)
Arrays.asList(1,2,3,4).forEach(System.out::println);
// 1 - can call methods of an element
// 2 - would need reference to containing object to remove an item
// (TODO: someone please confirm / deny this)
// 3 - functionally separates iteration from the action
// being performed with each item.
Arrays.asList(1,2,3,4).stream().forEach(System.out::println);
// Same capabilities as above plus potentially greater
// utilization of parallelism
// (caution: consequently, order of execution is not guaranteed,
// see [Stream.forEachOrdered][stream-foreach-ordered] for more
// information about this).
如果有的话,还有哪些其他方法?
(顺便说一句,我的兴趣根本不是出于对 optimize performance 的渴望;我只是想知道作为开发人员可以使用哪些表格。)
最佳答案
三种循环形式几乎相同。增强的 for
循环:
for (E element : list) {
. . .
}
是,根据Java Language Specification , 相同 与显式使用带有传统 for
循环的迭代器相同。在第三种情况下,您只能通过删除当前元素来修改列表内容,并且只能通过迭代器本身的 remove
方法来进行。使用基于索引的迭代,您可以以任何方式自由修改列表。但是,添加或删除当前索引之前的元素可能会导致循环跳过元素或多次处理相同的元素;进行此类更改时,需要适当调整循环索引。
在所有情况下,element
都是对实际列表元素的引用。没有任何迭代方法会复制列表中的任何内容。 element
内部状态的变化总是会在列表中对应元素的内部状态中看到。
本质上,迭代列表只有两种方法:使用索引或使用迭代器。增强的 for 循环只是 Java 5 中引入的一种语法快捷方式,以避免显式定义迭代器的乏味。对于这两种样式,您可以使用 for
、while
或 do while
block 来提出本质上微不足道的变体,但它们都归结为相同事情(或者,更确切地说,两件事)。
编辑:正如@iX3 在评论中指出的那样,您可以使用 ListIterator
在迭代时设置列表的当前元素。您需要使用 List#listIterator()
而不是 List#iterator()
初始化循环变量(显然,必须将其声明为 ListIterator
而不是 Iterator
)。
关于java - 在 Java 中迭代列表的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18410035/