【问题标题】:How Do I add to an ArrayList within a HashMap while iterating如何在迭代时添加到 HashMap 中的 ArrayList
【发布时间】:2021-07-31 11:37:30
【问题描述】:

在为我的档案大学项目学习 LWJGL 教程系列时,我将游戏项目添加到具有关联 Mesh 类的世界中,

如果我要向世界添加许多共享相同网格的对象,将游戏项目列表关联到一种网格类型然后从那里渲染会更有效

private Map<Mesh, List<GameItem>> meshMap;

meshMap = new HashMap();

     public void addDynamicGameItem(DynamicGameItem dynamicGameItem) {
    numGameItems++;
        Mesh[] meshes = dynamicGameItem.getMeshes();
        for(Mesh mesh : meshes) {
            List<GameItem> list = tempMap.get(mesh);
            if (list == null) {
                list = new ArrayList<>();
                tempMap.put(mesh, list);
            }
            list.add(dynamicGameItem);
        }
}

直到我尝试在迭代哈希图时向世界添加新游戏项目之前,这一切正常,对 addStaticGameItem 的任何后续调用似乎都会将新项目的游戏逻辑添加到世界,但没有添加网格正确,因此根本看不到。

这里是调用 hashmap 进行渲染的地方:

Map<Mesh, List<GameItem>> mapMeshes = scene.getGameMeshes();
    for (Mesh mesh : mapMeshes.keySet()) {
        if(mesh.getMaterial() != null) {
            sceneShaderProgram.setUniform("material", mesh.getMaterial());
            Texture text = mesh.getMaterial().getTexture();
            if (text != null) {
                sceneShaderProgram.setUniform("numCols", 
                text.getNumCols());
                sceneShaderProgram.setUniform("numRows", 
                text.getNumRows());
            }
        }
          mesh.renderList(mapMeshes.get(mesh), (GameItem gameItem) -> {
                    sceneShaderProgram.setUniform("selected", 
                    gameItem.isSelected() ? 1.0f : 0.0f);
                    Matrix4f modelViewMatrix = 
                    transformation.buildModelViewMatrix(gameItem, 
                    viewMatrix);
                    sceneShaderProgram.setUniform("modelViewMatrix", 
                    modelViewMatrix);
                    Matrix4f modelLightViewMatrix = 
                    transformation.buildModelLightViewMatrix(gameItem, 
                    lightViewMatrix);
                    sceneShaderProgram.setUniform("modelLightViewMatrix", 
                    modelLightViewMatrix);
                }
        );
    }

那么如何在迭代时正确地将新值添加到 Hashmap 列表中?

编辑:这行得通

public void updateMeshMap(){
    if(!tempMap.isEmpty()){
        for(Mesh m : tempMap.keySet()){
            List list = meshMap.get(m);
            if (list == null) {
                list = new ArrayList<>();
                list.addAll(tempMap.get(m));
                meshMap.put(m, list);
            }else{
                list.addAll(tempMap.get(m));
            }
        }
    }
    tempMap = new HashMap<Mesh, List<GameItem>>();
}

【问题讨论】:

  • 您似乎根本没有在for (Mesh mesh : mapMeshes.keySet()) { 循环中调用addStaticGameItem...所以当您说“直到我尝试向世界添加新的游戏项目之前,您在说什么?当 hashmap 被迭代时”?
  • 在为世界创建新对象和网格时,我从另一个类调用 addstaticgameitem,稍后我使用相同的方法创建新游戏项目,除了现在正在迭代哈希图,新项目没有被添加,所有以前的项目都是在类初始化期间添加的

标签: java loops arraylist hashmap lwjgl


【解决方案1】:

您实际上不能在迭代时向 HashMap 添加新值。但是您可以尝试创建一个临时映射tempMap,将新项目添加到此tempMap,然后在迭代后更改您的原始HashMap(您可以使用meshMap.putAll(tempMap))。

还可以查看HashMap documentation 在哪里可以找到

这个类的所有“集合视图”返回的迭代器 方法”是快速失败的:如果地图在任何结构上被修改 迭代器创建后的时间,除了通过 迭代器自己的remove方法,迭代器会抛出一个 ConcurrentModificationException。

【讨论】:

  • 我之前就试过了,由于某种原因,在调用 meshmap.putall(tempmap) 之后,其中 temp map 有两个新对象,meshmap 的长度没有改变,我仍然看不到新的游戏中的对象意味着添加新游戏项目网格时出现问题
  • 您可能正在使用地图中已存在的密钥添加新条目。然后您需要在此键的列表中添加新值。您可以检查每个put(),因为它返回与键关联的先前值,如果没有键映射,则返回 null 或使用map.containsKey(key)
  • 关键是网格,从技术上讲,关键应该已经存在,因为我正在添加一个已经存在于哈希图中的新对象类型,新游戏项,相同的网格,你也知道我为什么不尝试向 hashmap 添加项目时出现并发修改异常?
  • 那么你应该使用ArrayList&lt;GameItem&gt; gi = map.get(key); 之后就像if (gi == null) { gi = new ArrayList&lt;GameItem&gt;(); gi.add(myGameItem); map.put(key, gi); } else { if(!gi.contains(myGameItem)) gi.add(myGameItem); } 而不是put()。因为 HashMap 存储唯一的键值条目,而具有相同键的 .put() 将覆盖旧值
  • 以ConcurrentModificationException为代价,据我记忆,是迭代器抛出的,也就是Iterator it之类的东西。这有历史根源,在 Java 1.2 中出现了集合和迭代器,在那些日子里,在迭代集合时无法避免 显式 使用迭代器,因此,从迭代器中抛出错误方法,您很可能不会使用,因此您不会看到它。
猜你喜欢
  • 2017-06-12
  • 1970-01-01
  • 2016-09-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-02
  • 2011-01-08
  • 1970-01-01
相关资源
最近更新 更多