0

I'm trying to add an Integer to an array list using and iterator. It crashes at the third call to .next() of the iterator. Here is the stack trace and code

Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:886)
    at java.util.ArrayList$Itr.next(ArrayList.java:836)
    at quicksort.test.generateSorted(test.java:33)
    at quicksort.test.main(test.java:17)
Java Result: 1


public static int[] generateSorted(final int length, final int minVal, final int maxVal)
{
    ArrayList<Integer> data = new ArrayList<>(length);
    data.add(getRandomVal(minVal, maxVal));
    ListIterator<Integer> itr = data.listIterator();
    boolean added;
    for(int i = 0; i < length; i++)
    {
        added = false;
        int rndNum = getRandomVal(minVal, maxVal);
        while(itr.hasNext() && !added)
        {

            System.out.println(rndNum);
            Integer currentNum = itr.next();
            if(currentNum >= rndNum)
            {
                itr.add(rndNum);
                added = true;
            }
        }

        if(!added)//add to end of arrayList
            data.add(rndNum);
    }

    return data.stream().mapToInt(i -> i).toArray();
}

How can it be a concurrent modification when everything in the project is single threaded? If an itterator can't add

As an aside, what's the difference between new ArrayList<>(size) and new ArrayList(size)? Netbeans gives me a warning with the second but still compiles fine.

EDIT: oops typo, I also meant to ask what the difference is with ArrayList(size)

4
  • new ArrayList<>(size) uses type inference to work out what the generic type of the ArrayList is, while new ArrayList(size) creates a raw (untyped) ArrayList. You should always use typed generics wherever possible so that you have type safety. Commented Aug 14, 2014 at 17:23
  • Which is line 17 in your code? Commented Aug 14, 2014 at 17:25
  • @JonK that was actually a typo in the question, I didn't know what was possible. What is the difference bewtween new ArrayList<Integer>(size) and not having anything where Integer is? Commented Aug 14, 2014 at 17:30
  • 1
    That's a new feature of Java 7 designed to cut down on boilerplate code. The thinking is that you already specified what the generic type is once when you wrote ArrayList<Integer> data, so making you define it again when you instantiate it is unnecessary - the compiler can work it out for itself. It's known as the diamond operator, and is effectively just shorthand for what you used to write. Commented Aug 14, 2014 at 17:33

3 Answers 3

3

The exception is due to you modifying the List while still using an Iterator. Iterators need to maintain state between calls to keep track of where it is. If you modify the underlying List, the Iterator's state becomes invalid, and it can no longer guarantee correct operation. This means you can not use any methods that modify a List, while you are currently using an Iterator. You can still modify the List through an Iterator because the Iterator can now maintain it's internal state and guarantee correct operation on later calls to the iterator.

There are a couple of solutions to your problem. The first is to recreate the iterator every time you you edit the underlying list. You should be doing this anyways as it appears you are trying to keep the list sorted and if you don't start at the beginning you won't have a good sort. The second solution is to add all the numbers into the list and then sort it using something like Collections.sort

Solution 1:

List< Integer > list = new ArrayList<>();
for( int i = 0; i < length; i++ ) {
    Iterator< Integer > itr = list.listIterator();
    // Generate and add number to list
}

Solution 2:

List< Integer > list = new ArrayList<>();
for( int i = 0; i < length; i++ ) {
    int num = ...; // Generate number
    list.add( num );
}
Collections.sort( list );

The warning is because you are not providing generic arguments to a generic class. It goes away when you add the '<>' because that tells the compiler to infer the generic arguments. It was recently added to reduce the amount of code required to create something like this.

List< Map< String, Map< String, List< String > > > > list1 = new ArrayList< Map< String, Map< String, List< String > > > >();
// Becomes
List< Map< String, Map< String, List< String > > > > list2 = new ArrayList<>();
Sign up to request clarification or add additional context in comments.

2 Comments

If he's not accessing indexs at random, he could use a LinkedList which allows insertion and removal during iteration
It would still corrupt the state of the Iterator. It wouldn't matter which type of list is used as they all need to follow the same contract, don't use List methods when using an Iterator. Although in this case a LinkedList would probably be faster when creating the List, but the question wasn't about what is faster/slower.
1

ConcurrentModificationException is thrown when collection that is being iterated using iterator is modified during the iteration not via the iterator.

This is exactly what you do in line:

data.add(rndNum);

when you access the list directly. Use itr.add() instead as you did in previous fragment of your code sample.

1 Comment

but would that always add it to the end?
1

Your data.add(rndNum); is adding directly to your ArrayList without using the ListIterator. That causes the iterator to throw ConcurrentModificationException when it notices that the list has changed.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.