Java foreach NoSuchElementException

标签 java foreach iterator iteration java-7

前几天,我们在应用程序日志中的这段代码中发现了一个相当尴尬的异常:

 final LIST currentSinks = this.sinks;
 if (null != currentSinks && !currentSinks.isEmpty())
 {
     for (final DataSink<? super T> sink : currentSinks)// **the exception is thrown here**
     {
         sink.updated(oldValue, newValue);
     }
 }

其中LIST

public abstract class AbstractDataSource<T, LIST extends Collection<DataSink<? super T>>>

使用的实现是ArrayList。它只是抛出 NoSuchElementException 。说实话我不太明白为什么。无论我尝试什么,都得到了预期的行为:没有通过 for 进行迭代。

堆栈跟踪的第一行:

java.util.NoSuchElementException caught here: java.util.ArrayList$Itr.next(ArrayList.java:834)

任何提示或解释将不胜感激。

编辑 也许一个好的起点是隔离 UT 中的行为。对此有什么想法吗?

最佳答案

好吧,我会努力总结评论中讨论的内容。谢谢大家,并自由编辑这个答案。

错误描述感觉像是并发错误,所以我们的理论是:

probably another thread removed an element between the Iterator's hasNext() and next() call, that happens behind the scenes in the for(:) loop (thanks Steve!).

那么,让我们测试一下我们的理论:

1) 首先,list 类型是 ArrayList,从 ArrayList 文档我们可以得到:

ArrayList is not synchronized, so if you need multi-threaded access, consider using List l = Collections.synchronizedList(new ArrayList(...));

2) 然后我们检查源代码以查找对 NoSuchElementException 的引用:在 java.util.ArrayList.java 上未发现任何情况,但 java.util.AbstractList.java 中出现了五次,其中最有趣的是:

   // under: public ListIterator<E> listIterator(final int index) {
   //        return new ListIterator<E>() {
   // line 1040:
   /**
   * Retrieves the next object from the list.
   *
   * @return The next object.
   * @throws NoSuchElementException if there are no
   *         more objects to retrieve.
   * @throws ConcurrentModificationException if the
   *         list has been modified elsewhere.
   */
  public E next()
  {
      if (position == size)
        throw new NoSuchElementException();
      position++;
      return i.next();
  }

回到我们的理论,我们可以说:

  • 是的,这是可能的。 ArrayList 未同步 (1),并且在任何并发修改检查之前,iterator.next() 会在某个时刻抛出 NoSuchElementException (2).
  • 只有找到问题根源并重现它时才能证明这一点(UT 可能是最好的选择)。在那之前,这可能是您最好的选择。

希望能帮助您解决问题!

关于Java foreach NoSuchElementException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28594002/

相关文章:

java - 如何确保计时器任务在共享环境中为特定 JVM 运行。有什么办法吗?

传输字节数组时出现 Java OutOfMemory 问题

c++ - 如何使用 C++ Boost 的 regex_iterator()

c++ - 在没有显式嵌套声明的情况下在另一个类的命名空间中声明一个类

java - 无法将数据从android插入到MySQL

javascript - 以编程方式确定是否可以在对象上运行 for 循环的最佳解决方案

PHP foreach 复制输出数据的最后一次迭代

c# - 为什么在使用 foreach 时不执行此 LINQ 查询?

c++ - 对存储在列表中的对象使用类函数,通过迭代器访问

java - 使用 Java 运行 C++ 程序