36

假设我有一个类似的列表:

List<String> list = new ArrayList<>();
list.add("a");
list.add("h");
list.add("f");
list.add("s");

在遍历此列表时,我想在列表末尾添加一个元素。但我不想遍历新添加的元素,因为我想迭代到列表的初始大小。

for (String s : list)
     /* Here I want to add new element if needed while iterating */

有人可以建议我怎么做吗?

4

6 回答 6

50

您不能为此使用 foreach 语句。foreach 在内部使用迭代器:

此类的 iterator 和 listIterator 方法返回的迭代器是快速失败的:如果在创建迭代器后的任何时间对列表进行结构修改,除了通过迭代器自己的 remove 或 add 方法之外的任何方式,迭代器将抛出 ConcurrentModificationException。

(来自 ArrayList javadoc)

在 foreach 语句中,您无权访问迭代器的 add 方法,并且无论如何这仍然不是您想要的 add 类型,因为它不会在末尾追加。您需要手动遍历列表:

int listSize = list.size();
for(int i = 0; i < listSize; ++i)
  list.add("whatever");

请注意,这仅对允许随机访问的列表有效。您可以通过检查列表是否实现 RandomAccess 标记接口来检查此功能。ArrayList 具有随机访问权限。链表没有。

于 2012-06-24T12:21:20.387 回答
9

遍历列表的副本并将新元素添加到原始列表中。

for (String s : new ArrayList<String>(list))     
{
    list.add("u");
}

请参阅 如何制作 List 类型的 ArrayList 对象的副本?

于 2012-06-24T12:17:16.357 回答
8

只需迭代老式方式,因为您需要显式索引处理:

List myList = ...
...
int length = myList.size();
for(int i = 0; i < length; i++) {
   String s = myList.get(i);
   // add items here, if you want to
}
于 2012-06-24T12:18:41.653 回答
3

您可以迭代原始列表的副本(克隆):

List<String> copy = new ArrayList<String>(list);
for (String s : copy) {
    // And if you have to add an element to the list, add it to the original one:
    list.add("some element");
}

请注意,在迭代列表时甚至不可能将新元素添加到列表中,因为它会导致ConcurrentModificationException.

于 2012-06-24T12:16:36.833 回答
1

为此,我将元素添加到一个新的空 tmp 列表,然后使用addAll(). 这可以防止不必要地复制大型源列表。

想象一下当 OP 的原始列表中有几百万个项目时会发生什么;有一段时间你会吸收两倍的内存。

除了节省资源之外,这种技术还可以防止我们不得不求助于 80 年代风格的 for 循环和使用在某些情况下可能没有吸引力的有效数组索引。

于 2012-06-24T12:20:34.853 回答
0

为了帮助解决这个问题,我创建了一个函数来使它更容易实现。

public static <T> void forEachCurrent(List<T> list, Consumer<T> action) {
    final int size = list.size();
    for (int i = 0; i < size; i++) {
        action.accept(list.get(i));
    }
}

例子

    List<String> l = new ArrayList<>();
    l.add("1");
    l.add("2");
    l.add("3");
    forEachCurrent(l, e -> {
        l.add(e + "A");
        l.add(e + "B");
        l.add(e + "C");
    });
    l.forEach(System.out::println);
于 2021-01-05T20:31:02.727 回答