我的代码中有一个要求,我们需要抓住ArrayIndexOutOfBoundsException
并继续推进其他元素。
然而,当我尝试这样做时,我得到ConcurrentModificationException
以下代码是我想要的,但它会在ConcurrentModificationException
line #1
例外
请注意,list.remove(1000)不会导致任何问题,但list.remove(-1)会导致
public class Test1 {
public static void main(String[] argv) {
test(new ArrayList<>());
}
public static void test(List<Integer> list) {
list.add(42);
Iterator<Integer> it = list.iterator();
try {
list.remove(-1);
} catch (Exception e) {
System.out.println(e);
}
try {
if (it.next() != 42);//Line #1
} catch (Exception e) {
System.out.println(e);
}
}
}
有人可以帮我理解这种行为吗?我该如何解决这个问题呢?
答案 0 :(得分:2)
因为你已经从列表中获取了一个迭代器,同时直接从列表中删除了项,所以迭代器就哭了。
一旦声明迭代器,只使用迭代器进行修改。
所以在第一个try块中使用/通过迭代器而不是直接在列表中删除。找到元素并从迭代器中删除。
it.remove();
答案 1 :(得分:2)
解决此问题的最简单方法是不将否定索引传递给list.remove()
。
发生第二个异常的原因是remove
执行部分范围检查,仅检查传递的index
是否过大。它不会检查它是否为负数,因为在这种情况下它依赖于支持数组的访问来抛出异常。
因此,对于负数索引,modCount
的{{1}}会在ArrayList
被抛出之前递增。因此,尝试在捕获此异常后继续遍历列表会抛出ArrayIndexOutOfBoundsException
。
ConcurrentModificationException
请注意,public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index); // ArrayIndexOutOfBoundsException is thrown here
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
不会导致此问题,因为list.remove(1000)
会在IndexOutOfBoundsException
递增之前被抛出。
当然,如果元素删除成功,您可能仍然会失败modCount
,因为在迭代它时从ConcurrentModificationException
安全删除元素的唯一方法是使用{{1 }} List
方法。
还有一件事 - 我不确定您打算致电Iterator
还是remove()
。前者(由编译器选择的那个)尝试删除指定索引处的元素,而后者在找到时删除指定的元素。
对于public E remove(int index)
,即使您要按元素删除,将public boolean remove(Object o)
传递给该方法也会尝试按索引删除。如果要按元素删除,则应传递引用类型 - List<Integer>
。