【问题标题】:How to add element in List while iterating in java?java - 如何在Java中迭代时在List中添加元素?
【发布时间】:2012-06-26 00:01:23
【问题描述】:

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

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

谁能建议我如何做到这一点?

【问题讨论】:

    标签: java collections arraylist loops


    【解决方案1】:

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

    这个类的迭代器和listIterator返回的迭代器 方法是快速失败的:如果列表在任何结构上被修改 迭代器创建后的时间,除了通过 迭代器自己的删除或添加方法,迭代器会抛出一个 ConcurrentModificationException。

    (来自 ArrayList javadoc)

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

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

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

    【讨论】:

      【解决方案2】:

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

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

      How to make a copy of ArrayList object which is type of List?

      【讨论】:

        【解决方案3】:

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

        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
        }
        

        【讨论】:

        • 不,不会。它会在使用迭代器并在迭代时添加元素时,但在您自己进行迭代时不会。
        • OPs 想要“迭代到初始大小”。
        【解决方案4】:

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

        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

        【讨论】:

          【解决方案5】:

          我通过将元素添加到一个新的空 tmp 列表中,然后使用 addAll() 将 tmp 列表添加到原始列表中来做到这一点。这可以防止不必要地复制大型源列表。

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

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

          【讨论】:

            【解决方案6】:

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

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2012-07-22
              • 2015-02-07
              • 2011-12-23
              • 1970-01-01
              • 2011-11-16
              • 2012-05-08
              • 1970-01-01
              • 2022-11-22
              相关资源
              最近更新 更多