0

I have a Map<String, ClassA> results.

When I do this, I get a ConcurrentModificationException:

results.entrySet().stream().map((entry) -> {
    ClassA objA = entry.getValue();
    if(objA.getList() != null) {
        objA.getList().forEach(x -> {
            if(x.getAttr() != null && x.getAttr.containsKey(key)) {
                List<String> y = x.getAttr().get(key);
                y.replaceAll(ClassB::transformationFunc);
            }
        });
    }
})

Basically what I am trying to do is if my results, has a value of ClassA, check for each element of the list if there is any Attribute with a given key. If so, replace the values of the key with a given transformation function.

public static String transformationFunc(String input) {
    try {
        JSONObject inputJson = (JSONObject) jsonParser.parse(input);
        return String.format("%s_%s", inputJson.get(key1), inputJson.get(key2));
    } catch (ParseException e) {
        //log
        //throw
    }
}
4
  • 2
    Possible duplicate of Java Concurrent Modification Exception Error Commented Nov 7, 2017 at 11:26
  • 2
    Could we see the code of ClassB::transformationFunc ? Commented Nov 7, 2017 at 11:44
  • @AlexandreDupriez Updated question with transformationFunc Commented Nov 7, 2017 at 15:40
  • Interesting - assuming you are using a JDK implementation of List, replaceAll will flag your list as mutated after all its elements have been replaced. But I cannot see from your code where and when the co-modification occurs. Do you have the stack trace associated to the ConcurrentModificationException? Commented Nov 7, 2017 at 16:08

1 Answer 1

4

Basically, you get a ConcurrentModificationException whenever you modify a collection that you are iterating over.

The only way in which you are allowed to modify a collection that you are iterating over is by explicitly using an Iterator. If you want to do work on a collection while you're iterating over it, you have to do it on a working copy of the collection instead.

Sign up to request clarification or add additional context in comments.

7 Comments

Would I need to replace the stream as well? Or do I just need to modify the foreach to use an iterator?
Yes, using a stream is also implicitly iterating over a collection (same as using forEach() or a foreach loop). You have to stream over a copy of the map.
To clarify: you only have to make a copy if your code is actually modifying the collection you're iterating over. By "modifying the collection" I mean "adding, removing or replacing elements" - unless you use some sort of weird observable collection, modifying the internals of objects that are parts of a collection does not constitute modifying the collection.
@Eugene: that's obviously hard to answer without seeing the internals of the methods in question or seeing a stacktrace.
@user1692342 it's not. your problem is elsewhere or you are not showing us everything. stacktrace.... also that exception would be thrown when you change the size of the collection you are streaming from, not the contents.
|

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.