0

I have a JSONObject where I need to rename some keys if a value exists in a map. This keeps throwing ConcurrentModificationException. Any way to achieve this instead of going through multiple loops?

JSONObject jsonObject = new JSONObject(result);
jsonObject.keySet().stream().forEach(key -> {
    if (someMap.containsKey(key)) { 
        jsonObject.put(someMap.get(key), jsonObject.get(key)); //Update the key in jsonObject with same value
        jsonObject.remove(key);
    }
});
User0911
  • 1,552
  • 5
  • 22
  • 33

1 Answers1

2

The documentation for ConcurrentModificationException explains this :

If a single thread issues a sequence of method invocations that violates the contract of an object, the object may throw this exception. For example, if a thread modifies a collection directly while it is iterating over the collection with a fail-fast iterator, the iterator will throw this exception.

Treat your problem by starting from someMap and you won't have to modify concurrently, hence the exception thrown.

A solution could thus be :

someMap.entrySet()
       .stream()
       .filter(entry -> jsonObject.has(entry.getKey()))
       .forEach(entry -> {
           jsonObject.put(entry.getKey(), entry.getValue());
           jsonObject.remove(entry.getKey());
       });

I don't exactly get why you'd put() and then remove() but then again this is not essential to the solution.

I assume you're using JSON-lib by the methods you're using, so you could also collect to a map :

someMap.entrySet()
       .stream()
       .filter(entry -> jsonObject.has(entry.getKey()))
       .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

JSONObject has a putAll(Map map) to make quick work of this.

It would be then a matter of benchmarking for whichever method suits you.

GDF
  • 157
  • 7