List.remove()对负值的行为有所不同

时间:2017-07-06 07:10:17

标签: java exception

我的代码中有一个要求,我们需要抓住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);
            }
        }
    }

有人可以帮我理解这种行为吗?我该如何解决这个问题呢?

2 个答案:

答案 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>