4

我正在迭代一个 java.util.LinkedList,在某些情况下我会向它添加一个元素。

LinkedList<Schedule> queue = new LinkedList<Schedule>(schedules);
ListIterator<Schedule> iterator = queue.listIterator();
while (iterator.hasNext()) {
    Schedule schedule = iterator.next();
    if(condition)
        iterator.add(new Schedule());
} 

问题是,例如,如果我从一个项目开始,则在下一次 iterator.next() 调用之前添加新项目并且迭代退出。

如何在迭代时将项目附加到 LinkedList 的末尾?请不要告诉我使用另一个列表并在第一个列表之后对其进行迭代,因为它不能正确解决我的问题。

4

5 回答 5

1

假设您没有使用迭代器的硬性要求,那么您可以将其搁置并按索引“迭代”列表:

LinkedList<Schedule> list;

for (int i = 0; i < list.size(); i++) {
   final Schedule schedule = list.get(i);
   if(condition)
       list.add(new Schedule());
}
于 2012-04-27T11:44:58.390 回答
1

如果您不能使用另一个列表,您可以通过计算您通过迭代器处理的元素数量并将其与列表的原始大小进行比较来解决您的问题:所有新元素都将位于列表的末尾,所以当您达到原始大小时,您可以结束循环。

LinkedList<Schedule> queue = new LinkedList<Schedule>(schedules);
int origSize = queue.size();
int currCount = 0;
ListIterator<Schedule> iterator = queue.listIterator();
while (iterator.hasNext()) {
  ++currCount;
  if (currCount >= origSize) {
    break; // reached the end of the original collection
  }
  Schedule schedule = iterator.next();
  if(condition)
    iterator.add(new Schedule());
} 

您还可以使用额外的列表来跟踪新元素,并在处理结束后将其添加到原始列表中:

LinkedList<Schedule> queue = new LinkedList<Schedule>(schedules);
LinkedList<Schedule> addQueue = new LinkedList<Schedule>();
ListIterator<Schedule> iterator = queue.listIterator();
while (iterator.hasNext()) {
  Schedule schedule = iterator.next();
  if(condition)
    addQueue.add(new Schedule());
} 
queue.addAll(addQueue);

另外,请注意iterator.add()

将指定元素插入列表(可选操作)。该元素被插入到 next 将返回的下一个元素(如果有)之前,并且插入到 next 将返回的下一个元素(如果有)之后。(如果列表不包含任何元素,则新元素将成为列表中的唯一元素。)新元素插入到隐式光标之前:对 next 的后续调用将不受影响,对 previous 的后续调用将返回新元素. (此调用将调用 nextIndex 或 previousIndex 返回的值加一。)

因此,如果列表中有多个元素,它不会将新元素添加到末尾,而是在当前元素和返回的元素之间添加next()。如果您确实想将新元素放在列表的末尾,请使用queue.add(...)

一般来说,不建议在通过迭代器遍历集合的同时修改集合,所以我建议你使用第二种方法(将额外的元素收集在一个单独的列表中,并在最后将它们添加到原始列表中)

于 2012-04-27T11:19:47.423 回答
1

正如其他人所建议的那样,在当前的 Collections 框架中,在迭代期间没有有效的、现成的对末端插入的支持。一项建议涉及重写迭代器。但我说,为什么不更进一步呢?

  1. 使用反射来修改Node类的可访问性,它为您提供了对双链接的引用,因此您不需要重新开始迭代get(index),不应该在高性能代码中使用。

  2. LinkedList明智地继承/派生和覆盖。

  3. 这很简单,但本着与上述 2 相同的精神,由于 JDK 是开源的,因此请根据需要借用源代码并编写自己的实现。

无论哪种情况,我都觉得这个功能应该由 Java LinkedList API 提供。

于 2018-08-10T20:57:01.627 回答
0

如何在迭代时将项目附加到 LinkedList 的末尾?

public void addWork(Scheduler scheduler)
{
 synchronized(scheduler)
 {
  queue.addLast(scheduler);
 }
}

您可以使用queue.removeFirst()从上到下处理队列中的项目。

public synchronized Scheduler getWork()
{
  return queue.removeFirst();
}

已编辑。

于 2012-04-27T11:40:25.237 回答
-1

只有在不使用迭代器进行迭代时才能满足在迭代时添加并在迭代中包含添加项的要求,因为每次添加元素时都无法重新计算迭代器的状态。如果您接受效率较低的get方法来进行迭代,那么问题就很简单了。例如

LinkedList<Schedule> queue = new LinkedList<Schedule>(){{add(new Schedule());add(new Schedule());add(new Schedule());}};
int i = 0;
// queue.size() is evaluated every iteration
while (i < queue.size()) {
    Schedule schedule = queue.get(i);
    if(i++ % 2 == 0)
        queue.add(new Schedule());
}
System.out.println(queue.size());

按预期打印 6。

于 2014-08-07T06:08:22.223 回答