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.components
和strData.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"
您不能在使用 each
或 eachWithIndex
迭代时从列表中删除元素,顺便说一句,这是一种不好的做法。 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']]
我使用 '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.components
和strData.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"
您不能在使用 each
或 eachWithIndex
迭代时从列表中删除元素,顺便说一句,这是一种不好的做法。 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']]