在 Java 中迭代列表的方法 [英] Ways to iterate over a list in Java

查看:26
本文介绍了在 Java 中迭代列表的方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对 Java 语言有点陌生,我试图让自己熟悉遍历列表(或其他集合)的所有方式(或至少是非病态的方式)以及其优缺点每个.

Being somewhat new to the Java language I'm trying to familiarize myself with all the ways (or at least the non-pathological ones) that one might iterate through a list (or perhaps other collections) and the advantages or disadvantages of each.

给定一个 Listlist 对象,我知道以下遍历所有元素的方法:

Given a List<E> list object, I know of the following ways to loop through all elements:

// 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

    // ...
}

注意:正如@a​​marseillan 指出的,这种形式是一个糟糕的选择用于迭代 Lists,因为实际实现get 方法可能不如使用 Iterator 有效.例如,LinkedList 实现必须遍历所有i 前面的元素得到第 i 个元素.

Note: As @amarseillan pointed out, this form is a poor choice for iterating over Lists, because the actual implementation of the get method may not be as efficient as when using an Iterator. For example, LinkedList implementations must traverse all of the elements preceding i to get the i-th element.

在上面的例子中,List 实现无法保存它的位置"以使未来的迭代更有效率.对于 ArrayList 来说并不重要,因为 get 的复杂性/成本是常数时间 (O(1)) 而对于 LinkedList> 它是否与列表的大小成正比 (O(n)).

In the above example there's no way for the List implementation to "save its place" to make future iterations more efficient. For an ArrayList it doesn't really matter, because the complexity/cost of get is constant time (O(1)) whereas for a LinkedList is it proportional to the size of the list (O(n)).

有关内置 Collections 实现的计算复杂性的更多信息,请查看 这个问题.

For more information about the computational complexity of the built-in Collections implementations, check out this question.

for (E element : list) {
    // 1 - can call methods of element

    // ...
}

迭代器

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

    // ...
}

函数式 Java

list.stream().map(e -> e + 1); // Can apply a transformation function for e

Iterable.forEachStream.forEach, ...

(来自 Java 8 的 Stream API 的映射方法(参见 @i_am_zero 的回答).)

Iterable.forEach, Stream.forEach, ...

(A map method from Java 8's Stream API (see @i_am_zero's answer).)

在实现 Iterable(例如,所有 Lists)的 Java 8 集合类中,现在有一个 forEach 方法,可以使用而不是 for 循环语句 如上所示.(这是另一个问题,提供了很好的比较.)>

In Java 8 collection classes that implement Iterable (for example, all Lists) now have a forEach method, which can be used instead of the for loop statement demonstrated above. (Here is another question that provides a good comparison.)

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

如果有的话,还有哪些方法?

What other ways are there, if any?

(顺便说一句,我的兴趣根本不是源于想要 优化性能;我只想知道作为开发人员的我可以使用哪些表单.)

(BTW, my interest does not stem at all from a desire to optimize performance; I just want to know what forms are available to me as a developer.)

推荐答案

这三种循环形式几乎相同.增强的 for 循环:

The three forms of looping are nearly identical. The enhanced for loop:

for (E element : list) {
    . . .
}

是,根据 Java 语言规范相同,效果是显式使用迭代器和传统的for 循环.在第三种情况下,您只能通过删除当前元素来修改列表内容,然后,只有通过迭代器本身的 remove 方法来完成.使用基于索引的迭代,您可以以任何方式自由修改列表.但是,添加或删除当前索引之前的元素可能会导致循环跳过元素或多次处理同一元素;进行此类更改时,您需要适当调整循环索引.

is, according to the Java Language Specification, identical in effect to the explicit use of an iterator with a traditional for loop. In the third case, you can only modify the list contents by removing the current element and, then, only if you do it through the remove method of the iterator itself. With index-based iteration, you are free to modify the list in any way. However, adding or removing elements that come before the current index risks having your loop skipping elements or processing the same element multiple times; you need to adjust the loop index properly when you make such changes.

在所有情况下,element 是对实际列表元素的引用.没有任何迭代方法会复制列表中的任何内容.element 内部状态的变化,总会在列表中对应元素的内部状态中看到.

In all cases, element is a reference to the actual list element. None of the iteration methods makes a copy of anything in the list. Changes to the internal state of element will always be seen in the internal state of the corresponding element on the list.

本质上,迭代列表只有两种方法:使用索引或使用迭代器.增强的 for 循环只是 Java 5 中引入的一种语法快捷方式,以避免显式定义迭代器的乏味.对于这两种样式,您可以使用 forwhiledo while 块来提出本质上微不足道的变体,但它们都归结为相同的事情(或者说,两件事).

Essentially, there are only two ways to iterate over a list: by using an index or by using an iterator. The enhanced for loop is just a syntactic shortcut introduced in Java 5 to avoid the tedium of explicitly defining an iterator. For both styles, you can come up with essentially trivial variations using for, while or do while blocks, but they all boil down to the same thing (or, rather, two things).

正如@iX3 在评论中指出的那样,您可以在迭代时使用 ListIterator 来设置列表的当前元素.您需要使用 List#listIterator() 而不是 List#iterator() 来初始化循环变量(显然,必须声明为 ListIterator 而不是而不是 Iterator).

As @iX3 points out in a comment, you can use a ListIterator to set the current element of a list as you are iterating. You would need to use List#listIterator() instead of List#iterator() to initialize the loop variable (which, obviously, would have to be declared a ListIterator rather than an Iterator).

这篇关于在 Java 中迭代列表的方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆