2

I am iterating over a List of CustomObject and while doing this iteration, I am mutating this object by adding a tag to tags list of this custom object. I am not adding or removing any CustomObject to or from customObjects (List). I am still getting java.util.ConcurrentModifcationException.

public class CustomObject {
    private List<Tag> tags;
    // Getter for Tag
    // Setter for tag
}

public class DummyClass {


  List<CustomObject> addMissingTag(List<CustomObject> customObjects) {
    for (CustomObject object:customObjects) { // line 5
      // following method adds a tag to tags list of CustomObject
      mutateObjectByAddingField(object); // line 7
      // Some Code      
    }
    return customObjects;
  }

  void mutateObjectByAddingField(CustomObject customObject) {//line 13
    Boolean found = false;
    for (Tag tag:customObject.getTags()) { // line 15
      if ("DummyKey".equalsIgnoreCase(tag.getKey())) {
        found = true;
        break;
      }
    }
    if (!found) {
      Tag tag = new Tag("DummyKey", "false");
      List<Tag> tags = customObject.getTags();
      tags.add(tag);
      customObject.setTags(tags);
    }
  }

}

Here is the stack trace:

java.util.ConcurrentModificationException: null
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901) ~[?:1.8.0_131]
    at java.util.ArrayList$Itr.next(ArrayList.java:851) ~[?:1.8.0_131]
    at DummyClass.mutateObjectByAddingField(DummyClass.java:15)
    at DummyClass.addMissingTag(DummyClass.java:7)

Does this mean we can get ConcurrentModifcationException even if we just try to modify the object and not remove or add from/to the list/collection?

Mr Matrix
  • 1,128
  • 2
  • 14
  • 28
  • Could you show us mutateObjectByAddingField method code? – Ismail Sep 11 '20 at 22:20
  • @Ismail: I updated the question with method's implementation – Mr Matrix Sep 11 '20 at 22:25
  • 2
    None of the code you’ve shown appears to be capable of causing a ConcurrentModificationException. Please create a [mre] that demonstrates the problem you’re having. – VGR Sep 11 '20 at 22:29
  • Your code shows no clue about the cause of the problem. This code works well. Could you show us the complete stacktrace? – Ismail Sep 11 '20 at 22:32
  • Thansk @Ismail, I updated the question with stacktrace. – Mr Matrix Sep 11 '20 at 22:36
  • Again, this code can't produce that stack trace. Please show a [mcve]. – Andy Turner Sep 11 '20 at 22:39
  • @AndyTurner When I first look to the stack trace, the problem resides in the method mutateObjectByAddingField – Ismail Sep 11 '20 at 23:17
  • @AndyTurner updated the question, does this code look okay now? – Mr Matrix Sep 11 '20 at 23:23
  • Your stack trace doesn’t appear to be authentic: the last line has `DummyClass.java` while the line before it has `DummyClass.jav`, and neither of them has a line number. This leads me to believe you massaged the stack trace in some way, rather than copying and pasting it directly. We can’t help you if you provide us with false information. A real stack trace tells you exactly which line of code produced the exception. – VGR Sep 12 '20 at 13:25
  • @VGR: Intention was not to provide false information but to not put production code here and that is why I recreated this minimal reproducible example from my production code. ```DummyClass.jav``` was clearly a typo. Outside of that, this is exactly what a minimal reproducible example should look like and the error originates at method: ```mutateObjectByAddingField``` @Ismail's answer is the correct solution for this problem and I am going to mark it as answer after validating it. – Mr Matrix Sep 12 '20 at 19:29
  • Changing the names is fine, but a stack trace isn’t of much use if it doesn’t tell us where the problem occurred. – VGR Sep 12 '20 at 21:02
  • @VGR This is the exact stack trace that I am getting for my production code (with names changed of-course). This stack trace clearly indicates that ```mutateObjectByAddingField``` method is where problem originates. Missing line numbers are irrelevant here as method names are clearly mentioned. Why do you think this stack trace isn't of much use? – Mr Matrix Sep 12 '20 at 21:38
  • Because I don’t yet know which line of code in `mutateObjectByAddingField` is causing the exception. – VGR Sep 12 '20 at 21:56
  • @VGR: Valid point, I added line numbers accordingly in this minimal reproducible example after reading the original stacktrace, let me know if this helps. – Mr Matrix Sep 12 '20 at 23:46

1 Answers1

1

First, you are using a List type in the for loop to iterate the elements, so the enhanced for statement is equivalent to a for using an iterator, as mentioned here, because List implements Iterator. Also, it's obvious from the stack trace.

When using Iterator, you can't make modifications on the list you are iterating, as mentioned GeeksForGeeks, you will get ConcurrentModificationException.

So, to solve this issue, you can for example implement explicitly the for loop using integers like below:

 for (int i=0;i < customObjects.length(); i++) {

      CustomObject object = customObjects.get(i);

      // following method adds a tag to tags list of CustomObject
      mutateObjectByAddingField(object);
      // Some Code      
 }
Ismail
  • 2,322
  • 1
  • 12
  • 26
  • This link does a good job of explaining differences between a traditional for loop and an iterator based for loop: https://stackoverflow.com/questions/33582050/what-is-a-difference-between-traditional-loop-and-for-each-loop One of the main advantage of using traditional for loop is that it allows you to modify the list and this is exactly what I needed. – Mr Matrix Sep 12 '20 at 00:28
  • Good, if the above lines answers your question, mark it as the right one to let other people know about it. If the answer need more detail, just edit it. – Ismail Sep 12 '20 at 04:37
  • Thanks @Ismail, I will do that after validating it during my testing. But this seems to be the correct solution. – Mr Matrix Sep 12 '20 at 19:30