为什么,在Java中使用增强的for循环,我不能改变我通过引用迭代的内容吗?不是迭代器,而是我迭代的数据类型的字段。
我希望迭代Map
s(MultiValueMap
s的列表),并检查地图的值是否可以更新。
我的问题是,改变它的实际逻辑嵌套在基于地图的其他循环(下面的大纲代码)中,并且我找不到在没有ConcurrentModificationException
的情况下进行替换的方法被抛出。原因是当我为一个循环处理ConcurrentModificationException
时,由于代码嵌套得很深,它会打破另一个循环。
在主循环中,遍历地图,我想创建一个新的地图,我只是添加东西,最后用它替换迭代地图。但这不起作用。
为什么会这样,我可以做些什么或研究什么来帮助我解决这个问题?
伪代码
for( Map loopMap : listOfMaps ) {
Map tempMap = new HashMap();
Set entrySet = loopMap.entrySet();
Iterator<MultiValueMap.Entry> iter = entrySet.iterator();
while( iter.hasNext() ) {
Map.Entry entry = (Entry) iter.next();
if( entry.getValue() == "test" ) {
tempMap.put( entry.getKey(), "new value" );
}
}
loopMap = tempMap;
}
为什么我不能改变地图所指的内容,即使我能够改变引用它的值?
答案 0 :(得分:2)
因为您使用的是参考值的副本,而不是直接引用。请注意,增强的for循环将在幕后为您使用Iterator
。它看起来像这样:
for (Iterator<YourClass> it = yourCollection.iterator(); it.hasNext(); ) {
YourClass yourClass = it.next();
//do whatever...
//and looks like you change yourClass value here
//which is a local variable, not the real object reference inside your collection
//also, you cannot add/remove an element here to the collection being iterated
//because this will throw a ConcurrentModificationException
}
解决方案是将所有新元素添加到新集合(List
,Map
,Set
或您正在使用的任何内容中),并且在您完成所有逻辑后,将其替换为当前收藏与您的新系列。这将是伪代码(我无法提供更准确的代码,因为您没有提供足够的信息):
Collection<YourData> newCollection = ... //initialize it
for (... : currentCollection) {
if (...) {
YourData yourData = new YourData();
//fill yourData variable
//...
//add it into newCollection
newCollection.add(yourData);
}
}
//roughly, you will end doing this or similar
currentCollection = newCollection;
使用您的新示例,要修改的元素将是Map
,因此请将新的键值对填充到新的Map
中,最后遍历此地图以替换当前地图中的元素:
Map<YourKey, YourValue> newMap = new HashMap<>(); //the implementation doesn't really matter for this one
for(Map.EntrySet<YourKey, YourValue> entrySet : currentMap.entrySet()) {
if (...) {
YourValue newValue = ...;
//compute the newValue data
//...
newMap.put(entrySet.getKey(), newValue);
}
}
for (Map.EntrySet<YourKey, YourValue> entrySet : newMap.entrySet()) {
currentMap.put(entrySet.getKey(), entrySet.getValue());
}