java - 不可能在 ArrayList.get() 上发生 IndexOutOfBound。有什么线索吗?

标签 java

我有一个非常奇怪的错误,想与您分享。

我有以下代码(简化):

public ArrayList<String> al = new ArrayList<String>();
public void doSomething() {
  int size = al.size();
  for(int i=0; i<size; i++) {
    if (al.get(i) != null) {
      System.out.println(al.get(i));
      String sPath = al.get(i);
      File fFile = new File(sPath);
      fFile.delete(); // Simplified. It has some error checking
    }
  }
}

我有一个错误,在生产环境中看到:

java.lang.IndexOutOfBoundsException: Index: 1, Size: 0
    at java.util.ArrayList.RangeCheck(Unknown Source)
    at java.util.ArrayList.get(Unknown Source)
    at MYCLASS.soSomething(MICLASS.java:1944)
    [...]

第 1944 行是 if (al.get(i) != null) {

什么!它如何提高 IndexOutOfBound?!

问题是错误不会重现。我只能在开发环境中引发一次,但无法尝试重现它(它没有再次引发)...所以无法在错误中寻找模式。

所以我唯一的选择很简单:读代码用脑。

于是我浏览了java.util.ArrayList.get()的代码:

public class ArrayList<E> [...]{
  public E get(int index) {
    RangeCheck(index);
    return (E) elementData[index];
  }
  private void RangeCheck(int index) {
    if (index >= size)
      throw new IndexOutOfBoundsException("Index: "+index+", Size: "+size);
  }
}

所以它抛出异常,因为 index >= size... 这怎么可能? for()0 扫到size-1...这是不可能的!它不能引发错误!

等一下!此代码不是线程安全的。也许另一个线程正在调用ArrayList 上的clear()remove*() ... 研究代码,这是不可能的。所以我运行它,在第 1944 行设置断点并观察那一刻的线程,实际上,其他正在运行的线程与这个问题无关。

还有其他线索吗?

Kernnigan 和 Pike:“调试 [...] 不可能发生的事情,唯一可靠的信息是它确实发生了。”

最佳答案

我看到以下候选人是如何发生的:

  • 循环中的某些东西改变了 i 的值。
  • 循环中的某些东西改变了 al 的大小,可能是删除元素的东西。
  • 某些东西正在用不同的 Collection 替换您的 Collection 。
  • 我见过这样的情况,其中循环的构造方式使主体在空集合的情况下甚至执行一次。尽管对于所描述的 for 循环来说这似乎不太可能。

调试这个的想法:用您自己的实现替换列表,记录对它的每次访问,并将所有实际功能委托(delegate)给标准实现。

如果需要,它可以打印新创建的异常的堆栈跟踪,以便识别调用它的位置。当从不同的线程访问它时,它甚至会抛出异常。

关于java - 不可能在 ArrayList.get() 上发生 IndexOutOfBound。有什么线索吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7752501/

相关文章:

java - Cassandra 需要_client_auth : true problem

java - 如何在java中执行ASCII减法

java - Java 中的倾斜或扭曲图像对象

java - JBoss EAP6 + HornetQ - 不确定如何创建到 HornetQ 的队列连接

java - 将java类导入jsp导致无法解析为类型错误

java - Java List<> 的问题

java - 将 boolean 对象数组转换为 boolean 原始数组?

java - 使用 Optional 验证输入

java - 获取错误 : conversion to Dalvik format failed: Unable to execute dex:

java - 如何使用 Java 创建带有表单控件的 Excel 文件?