2

I have an issue removing the 1st and 2nd element of my list even by using the iterator.

I have read the following threads but can't fix my issue (those were the most relevant but I checked other material as well):

ConcurrentModificationException when trying remove element from list

Iterating through a Collection, avoiding ConcurrentModificationException when removing objects in a loop

So my code looks like this:

List<List<String>> list = cnf.read();
List<List<String>> nlist = new ArrayList<>();
for (List<String> l : list) {
    if (l.size() <= 3) {
        nlist.add(l);
    } else {
        int size = l.size();
        while (size > 3) {
            List<String> three = l.subList(0, 2);
            three.add("Y" + (count++));
            //Iterator itr = l.iterator();
            ListIterator itr = l.listIterator();
            int v = 0;
            while (itr.hasNext()) {
                itr.next();
                if (v == 0 || v == 1) {
                    itr.remove();
                    v++;
                }
            }
            l.add(0, "Y" + (count++));
            size--;
            nlist.add(three);
        }
        nlist.add(l);
    }
}
for (List<String> l : nlist) {
    System.out.println(l.toString());
    System.out.println(l.size());
}

I get a ConcurrentModificationException at the print statement here :

System.out.println(l.toString());

I tried using iterators for my 2 for loops as well but It doesn't seem to make a difference! I am new to posting questions so let me know If I am doing it right! Thank you.

Community
  • 1
  • 1
  • Are you familiar with interface `java.util.ListIterator`? According to its _javadoc_, it allows modification of the list while traversing it. – Abra Apr 21 '19 at 22:03
  • @Abra Yes! I am using the iterator to do itr.remove(). This should allow me to remove the items I want from the list. However, It causes an exception. My guess is that it's because it is located in another loop (nested) so it's causing issues. I don't know how to fix it. – Mamoun Debbarh Apr 21 '19 at 22:07
  • The code you posted does not contain **ListIterator**. – Abra Apr 21 '19 at 22:09
  • @Abra So the line: Iterator itr = l.iterator(); Is not a ListIterator but a simple Iterator? I am checking it now to find a solution. It might be a lead. – Mamoun Debbarh Apr 21 '19 at 22:12
  • Even by using ListIterator it = l.listIterator();. I get the same exception. As I understood from the following post: https://techdifferences.com/difference-between-iterator-and-listiterator-in-java.html The main difference between the 2 methods is that list iterator allows you to modify and element and traverse the list in both directions. – Mamoun Debbarh Apr 21 '19 at 22:15
  • I can confirm the exception. I don't understand why and how `toString()` whould ever throw a `ConcurrentModificationException` without additional threads. – stonar96 Apr 21 '19 at 22:18
  • I suggest you post your updated code that uses `ListIterator`. Also, the problem may have to do with method `cnf.read(0)` whose code you did not post. – Abra Apr 21 '19 at 22:18
  • cnf.read() just returns a list of lists. The list is valid and verified as I hardcoded it for testing purposes. I will edit the code for ListIterator now. – Mamoun Debbarh Apr 21 '19 at 22:20
  • @Abra If you create an `ArrayList` containing two `ArrayList`s with multiple `String`s instead of `cnf.read()` it also throws the exception. That's how I have tested it. – stonar96 Apr 21 '19 at 22:24

1 Answers1

0

After A long debugging, here is the solution.

The sublist function passes by reference and not by value, a sublist created by ArrayList.subList call keeps a reference to the original list and accesses its elementData array directly.

For this reason, when adding an element to the "three" list, we alter the state of the original list. this happens here:

three.add("Y" + (count++));

A way of fixing it for this specific case is to create and initialize the "three" list the following way:

                String one = l.get(0);
                String two = l.get(1);
                List<String> three = new ArrayList<>();
                three.add(one);
                three.add(two);
                three.add("Y" + (count));

This allows us to manipulate our lists without getting Concurrency Exceptions (ConcurrentModificationException). However, if you are manipulating big lists, I would suggest you use another less hardcoded method for list creation.

I will mark this thread as answered and hope it helps people.

  • Nevertheless, I do not understand why the `ConcurrentModificationException` is thrown at all. `toString()` should use it's own `Iterator` and the list isn't modified after `toString()` was invoked. So there is still the question where the `ConcurrentModificationException` comes from. It would be nice if someone could answer that. – stonar96 Apr 22 '19 at 18:33
  • @stonar96 I think it's because we are iterating through 'nlist'. The iteration causes the exception because the lists it contains are altered the "wrong way". This is my best guess and I am not a pro though! – Mamoun Debbarh Apr 22 '19 at 19:11