在增强的for循环中更改迭代项的引用

时间:2014-08-06 17:06:39

标签: java for-loop reference

为什么,在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;
}

为什么我不能改变地图所指的内容,即使我能够改变引用它的值?

1 个答案:

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

解决方案是将所有新元素添加到新集合(ListMapSet或您正在使用的任何内容中),并且在您完成所有逻辑后,将其替换为当前收藏与您的新系列。这将是伪代码(我无法提供更准确的代码,因为您没有提供足够的信息):

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());
}