简体   繁体   中英

Concurrent exception in Groovy even when changes are made to another LinkedHashMap

I have created a new LinkedHashMap 'workingStrData' using 'strData' and I still get the error.

I am trying to remove some items from this LinkedHashMap based of another list.

The way strData is structured is

    strData = [components[{key1:value1}{key2:value2}...]]     

    def workingStrData = new LinkedHashMap(strData)
    List componentsToRemove = ['item1','item2'...]
    int itemsRemoved = 0

    workingStrData.components.eachWithIndex {
            comp, workingStrIndex ->
                println("Index: "+workingStrIndex+" Component: "+comp.number)

                def baditem = comp.number in componentsToRemove
                if (baditem) {
                    strData.components.remove(workingStrIndex - itemsRemoved)
                    itemsRemoved += 1
                }
        }

It is not complaining about the strData / workingStrData maps, it is complaining about the List referenced by the value of the "components" key in the map.

You know, the List you are actually iterating, and the List you actually call remove(int index) on.

You don't actually iterate or modify the map, so copying that is meaningless.

Eddiel is right, you can't modify array ( and strData.components is an array ) while you iterate it.

Even if you created a copy of root map def workingStrData = new LinkedHashMap(strData) the content of this map referencing the same data.

it means that workingStrData.components and strData.components referencing the same array.


groovy styled code to modify array:

def strData = [
    components:[
        [number:'111', name:'aaa'],
        [number:'222', name:'bbb'],
        [number:'333', name:'ccc'],
        [number:'444', name:'ddd'],
    ]
]
List componentsToRemove = ['222','333']

//--------------------------------------
// if you want to keep original data:
def modData = [
    components: strData.components.findAll{c-> c.number in componentsToRemove }
]

println "original           : $strData"
println "modified           : $modData"

//--------------------------------------
// if you want to modify existing data
strData.components.retainAll{c-> !( c.number in componentsToRemove) }
println "original (modified): $strData"

You cannot remove an element from a list while iterating with each or with eachWithIndex which by the way is a bad practice. Groovy offers much more elegant and simpler solutions.

As suggested, try retainAll() or as suggested here, try removeAll() :

def strData = [
    components : [
        [number: 'item0'],
        [number: 'item1']
    ]
]

def componentsToRemove = [
    'item1','item2'
]

componentsToRemove.each { removeIt ->
    strData.components.removeAll { it.number == removeIt }
}

assert strData.components == [[number: 'item0']]

You can not modify the map unless you use an iterator or you use a synchronized collection. This is by design in Java. Check https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#synchronizedMap-java.util.Map- to wrap your collection or, remove the elements using the iterator's own remove function.

In java, that would look like this:

Iterator<String> iterator = workingStrData.keySet().iterator();
while (iterator.hasNext()) {
    iterator.next();
    iterator.remove();
}

// workingStrData is empty at this point.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM