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?

+3


source to share


2 answers


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))

.

+2


source


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();

      

+2


source







All Articles