Groovy 中的并发异常,即使对另一个 LinkedHashMap 进行了更改

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

我使用 'strData' 创建了一个新的 LinkedHashMap 'workingStrData',但仍然出现错误。

我正在尝试从这个基于另一个列表的 LinkedHashMap 中删除一些项目。

strData 的结构方式是

    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
                }
        }

除非使用 iterator 或使用同步集合,否则无法修改地图。这是 Java 中的设计。检查 https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#synchronizedMap-java.util.Map- 以包装您的集合,或者使用迭代器自己的删除函数删除元素。

在 java 中,它看起来像这样:

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

// workingStrData is empty at this point.

它不是在抱怨 strData/workingStrData 映射,而是在抱怨映射中 "components" 键的值引用的 List

你知道,List 你实际上正在迭代,而 List 你实际上调用 remove(int index)

你实际上并没有迭代或修改地图,所以复制是没有意义的。

Eddiel 是对的,在迭代数组时不能修改数组(strData.components 是一个数组)。

即使您创建了根地图的副本 def workingStrData = new LinkedHashMap(strData) 此地图的内容引用了相同的数据。

表示workingStrData.componentsstrData.components引用同一个数组


groovy 修改数组的样式代码:

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"

您不能在使用 eacheachWithIndex 迭代时从列表中删除元素,顺便说一句,这是一种不好的做法。 Groovy 提供了更优雅、更简单的解决方案。

按照建议,尝试 retainAll() 或按照此处的建议,尝试 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']]