迭代时出现奇怪的 ConcurrentModificationException

A strange ConcurrentModificationException on iteration

this 可能是最接近我的情况,但这也没有帮助。

我在这里收到 ConcurrentModificationException:

for (Iterator<ProjectileBase> iterator = projectiles.iterator(); iterator.hasNext();) {
        ProjectileBase proj = iterator.next();  < here
        if (proj == null || !proj.isValid()) {
            iterator.remove();
            continue;
        }
        if (((!proj.ignoreRange()) ? proj.lived <= proj.data.getRange() : true)){
            proj.lived++;
            proj.onTick();
        } else {
            MissileHitEvent event = new MissileHitEvent(proj.shooter, proj.wand, proj, false, null);
            Bukkit.getPluginManager().callEvent(event);
            if (!event.isCancelled()) {
                iterator.remove();
                continue;
            } else {
                proj.lived = 0;
            }
        }
    }

尽管我按照建议做了here

列表是这样指定的:

private List<ProjectileBase> projectiles = new ArrayList<ProjectileBase>();

在 class 构造中初始化。有什么问题吗?

编辑: 控制台日志:

[10:01:58] [Craft Scheduler Thread - 3754/WARN]: Exception in thread "Craft Scheduler Thread - 3754" 
[10:01:58] [Craft Scheduler Thread - 3754/WARN]: org.apache.commons.lang.UnhandledException: Plugin MagicWands v1.0 generated an exception while executing task 247
    at org.bukkit.craftbukkit.v1_9_R2.scheduler.CraftAsyncTask.run(CraftAsyncTask.java:57)
    at com.destroystokyo.paper.ServerSchedulerReportingWrapper.run(ServerSchedulerReportingWrapper.java:22)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
Caused by: java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
    at java.util.ArrayList$Itr.next(Unknown Source)
    at io.jettymc.DataHolders.ProjectileManager.iterate(ProjectileManager.java:117)
    at io.jettymc.DataHolders.ProjectileManager.run(ProjectileManager.java:232)
    at org.bukkit.craftbukkit.v1_9_R2.scheduler.CraftTask.run(CraftTask.java:58)
    at org.bukkit.craftbukkit.v1_9_R2.scheduler.CraftAsyncTask.run(CraftAsyncTask.java:53)
    ... 4 more

编辑 2: 好吧,我想值得一提的是,我正在 Bukkit/Spigot(Minecraft 服务器和 API)上构建这个项目。但我怀疑这是这个错误的原因?

查看 ConcurrentModificationException 和 ArrayList 的文档

https://docs.oracle.com/javase/7/docs/api/java/util/ConcurrentModificationException.html

https://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html

要解决您的问题,请检查以下代码。

例如,

import java.util.*;

public class HelloWorld{

     public static void main(String []args){
        List<String> animals = new ArrayList<>();
        animals.add("Cat1");
        animals.add("Cat2");
        animals.add("Cat3");
        animals.add("Cat4");
        animals.add("Cat5");

        for(ListIterator<String> iterator = animals.listIterator(); iterator.hasNext();) {
            String name = iterator.next();
            if (name.equals("Cat2")) {
                iterator.remove();
                continue;
            }
            System.out.println(name);
        }
     }
}

干杯!!!

为了帮助缩小问题范围,有一个技巧可能会有所帮助。

假设 projectiles 是对 ArrayList 的唯一引用,您可以在迭代时临时用不可变列表替换它,因此只有 Iterator 可以修改列表。如果其他一些代码试图修改列表,则会发生异常,假设您的错误处理没有搞砸,这应该让您知道它发生在哪里。

示例:

List<ProjectileBase> projectilesHold = projectiles;
projectiles = Collections.unmodifiableList(projectiles);
try {
    for (Iterator<ProjectileBase> iterator = projectilesHold.iterator(); iterator.hasNext();) {
        // other code here is unchanged
    }
} finally {
    projectiles = projectilesHold;
}

代码将可修改列表保存在"hold"变量中,然后将列表包装起来使其不可修改。 finally 块将确保恢复可修改列表,无论如何。

for 循环迭代器随后被修改为使用 "hold" 中的可修改列表,因此其 remove() 方法有效,但 projectiles 字段现在在其他任何地方在迭代期间不可修改。

这仅用于调试。确定问题并改正后,再次删除逻辑。