我有一个非常奇怪的错误,想与您分享。
我有以下代码(简化):
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/