What is this currentmodificationerror

Discussion in 'Spigot Plugin Development' started by Kyllian, May 20, 2017.

  1. Hey, someone sent me this error of my plugin:

    Code (Text):
    20.05 13:12:20 [Server] INFO at java.lang.Thread.run(Thread.java:748) [?:1.8.0_131]
    20.05 13:12:20 [Server] INFO at net.minecraft.server.v1_8_R3.MinecraftServer.run(MinecraftServer.java:616) [paper-1.8.8-created-05.02:git-PaperSpigot-"8b18730"]
    20.05 13:12:20 [Server] INFO at net.minecraft.server.v1_8_R3.MinecraftServer.A(MinecraftServer.java:713) [paper-1.8.8-created-05.02:git-PaperSpigot-"8b18730"]
    20.05 13:12:20 [Server] INFO at net.minecraft.server.v1_8_R3.DedicatedServer.B(DedicatedServer.java:378) [paper-1.8.8-created-05.02:git-PaperSpigot-"8b18730"]
    20.05 13:12:20 [Server] INFO at net.minecraft.server.v1_8_R3.MinecraftServer.B(MinecraftServer.java:783) [paper-1.8.8-created-05.02:git-PaperSpigot-"8b18730"]
    20.05 13:12:20 [Server] INFO at org.bukkit.craftbukkit.v1_8_R3.scheduler.CraftScheduler.mainThreadHeartbeat(CraftScheduler.java:349) [paper-1.8.8-created-05.02:git-PaperSpigot-"8b18730"]
    20.05 13:12:20 [Server] INFO at org.bukkit.craftbukkit.v1_8_R3.scheduler.CraftTask.run(CraftTask.java:59) ~[paper-1.8.8-created-05.02:git-PaperSpigot-"8b18730"]
    20.05 13:12:20 [Server] INFO at me.kyllian.captcha.Captcha$5.run(Captcha.java:138) ~[?:?]
    20.05 13:12:20 [Server] INFO at java.util.HashMap$KeyIterator.next(HashMap.java:1461) ~[?:1.8.0_131]
    20.05 13:12:20 [Server] INFO at java.util.HashMap$HashIterator.nextNode(HashMap.java:1437) ~[?:1.8.0_131]
    20.05 13:12:20 [Server] INFO java.util.ConcurrentModificationException
    20.05 13:12:20 [Server] WARN [Captcha] Task #17 for Captcha v3.29 generated an exception
    What can be causing it?

    line 138: for (UUID uuid : Data.relogTime.keySet()) {

    Code around it:

    Code (Text):
    public void relogDelay() {
            new BukkitRunnable() {
                @Override
                public void run() {
                    if (Data.relogTime.isEmpty()) {
                        return;
                    }
                    for (UUID uuid : Data.relogTime.keySet()) {
                        int timeOld = Data.relogTime.get(uuid);
                        Data.relogTime.remove(uuid);
                        Data.relogTime.put(uuid, timeOld - 1);
                        if (Data.relogTime.get(uuid) <= 0) {
                            Data.relogTime.remove(uuid);
                        }
                    }
                }
            }.runTaskTimer(this, 0, 20);
        }
     
  2. You are iterating over a map keySet and, at the same time, you are removing an item from the same map
     
  3. You are removing values from a Map that you are currently looping through.
     
  4. So a 1 tick delay should help?
     
  5. Or should this fix it:

    Code (Text):
    for (UUID uuid : Data.relogTime.keySet()) {
                        int timeOld = Data.relogTime.get(uuid);
                        if (timeOld - 1 <= 0) {
                            Data.relogTime.remove(uuid);
                            return;
                        }
                        Data.relogTime.remove(uuid);
                        Data.relogTime.put(uuid, timeOld - 1);
                    }
     
  6. Use a iterator...
    https://docs.oracle.com/javase/7/docs/api/java/util/Iterator.html
    https://www.tutorialspoint.com/java/java_using_iterator.htm
     
    • Agree Agree x 1
  7. so wot about learning java?
    ever occurred that may be smart?
     
    • Agree Agree x 1
  8. You cannot change a map while you are iterating over it
    This should fix it
    Code (Text):
        public void relogDelay() {
            new BukkitRunnable() {
                @Override
                public void run() {
                    Map DataBackup =new HashMap<>(Data.relogTime);
                    if (DataBackup.isEmpty()) {
                        return;
                    }
                    for (UUID uuid : DataBackup.keySet()) {
                        int timeOld = Data.relogTime.get(uuid);
                        Data.relogTime.remove(uuid); //<-- If you are using an hashmap this can be removed
                        Data.relogTime.put(uuid, timeOld - 1);
                        if (Data.relogTime.get(uuid) <= 0) {
                            Data.relogTime.remove(uuid);
                        }
                    }
                }
            }.runTaskTimer(this, 0, 20);
        }
     
    • Optimistic Optimistic x 1
  9. keySey()#iterator(); Since a long time....
     
  10. Why would you have a scheduler? People have already said countless of times just to use an iterator.
     
  11. Not even gonna work... Please stop spoonfeeding. Not useful.. And also, bad spoonfeed...
     
    • Agree Agree x 1
  12. I see I only changed

    Map DataBackup =new HashMap<>(Data.relogTime);

    to

    Map<UUID, Integer> DataBackup = new HashMap<>(Data.relogTime);
     
  13. I'll try that!
     
  14. LOL. You have something called an entrySet which have an iterator.

    EDIT: you also have a keySet
     
  15. Don't follow his bad spoonfeeding. It won't work. Use a iterator on a hashmap. Basically you copy the hashmap and iterate over that and remove the user from the original hashmap.
     
    • Agree Agree x 1
  16. Alright I think this must be quite good.

    Code (Text):
    Iterator<UUID> itr = Data.relogTime.keySet().iterator(); // makes an irerator over the UUID in a map. so it returns uuids
                    while(itr.hasNext()) { // if the list has something in it
                        itr.next(); // then set it the the next one
                        int timeOld = Data.relogTime.get(itr); // try getting the old number
                        if (timeOld - 1<= 0) { // if the time -1 is smaller then 0
                            itr.remove(); // then remove the uuid from the list
                            return; // stop
                        }
                        itr.remove(); // if its not still remove it
                        Data.timeLeft.put(itr, timeOld - 1); // and put the time in there.
                    }
    Only thing is. I cant put an irerator<UUID> in line Data.timeLeft.put(itr, timeOld - 1);
    but i'm quite sure its should return UUID's?
     
  17. Not quite really.
    Use, UUID uuid = itr.next();
    Also, you realize you only remove from the iterator right? Not from the Original hashmap.