List.remove () behaves differently for negative values
I have a requirement in our code where we need to catch ArrayIndexOutOfBoundsException
and move forward with other elements.
However, when I try to do this, I get ConcurrentModificationException
The following code is what I want, but it throws an exception ConcurrentModificationException
atline #1
Note that list.remove (1000) does not cause any problems, but list.remove (-1) does
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);
}
}
}
Can someone help me understand this behavior and how can I fix this problem?
source to share
The easiest way to fix this problem is to not pass a negative index to list.remove()
.
The reason this second exception is thrown is because it remove
is doing a partial range check that only checks if the index
size passed is too large. It does not check if this is negative, as it relies on the backing array access to throw an exception in this case.
Thus, for a negative index, it modCount
ArrayList
increases before being thrown away ArrayIndexOutOfBoundsException
. As a result, trying to continue iterating over the list after you catch this exception is being thrown 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;
}
Note that list.remove(1000)
this will not cause this problem, as it IndexOutOfBoundsException
will be selected before being modCount
enlarged.
Of course, if deleting an item was successful, you could still fail with ConcurrentModificationException
, as the only way to safely remove items from List
when iterating over it is to use the Iterator
remove()
.
One more thing - I'm not sure what you intended to call public E remove(int index)
or public boolean remove(Object o)
. The former (which was chosen by the compiler) tries to remove the element at the specified index, and the latter removes the specified element if found.
With a, List<Integer>
passing to int
this method will try to delete by index, even if you want to delete the element. If you want to remove an element, you must pass a reference type - list.remove(Integer.valueOf(-1))
.
source to share
Since you are already getting the iterator from the list and in the meantime you are removing the elements from the list, so the iterator cried.
Once you have to declare that the iterator only uses the iterator to make changes.
So, in the first try, the block removes the use of / via the iterator, not the list directly. Find the element and remove it from the iterator.
it.remove();
source to share